# -*- coding: UTF-8 -*-
#/**
# * Software Name : pycrate
# * Version : 0.4
# *
# * Copyright 2016. Benoit Michau. ANSSI.
# *
# * This library is free software; you can redistribute it and/or
# * modify it under the terms of the GNU Lesser General Public
# * License as published by the Free Software Foundation; either
# * version 2.1 of the License, or (at your option) any later version.
# *
# * This library is distributed in the hope that it will be useful,
# * but WITHOUT ANY WARRANTY; without even the implied warranty of
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# * Lesser General Public License for more details.
# *
# * You should have received a copy of the GNU Lesser General Public
# * License along with this library; if not, write to the Free Software
# * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 
# * MA 02110-1301  USA
# *
# *--------------------------------------------------------
# * File Name : pycrate_core/utils_py2.py
# * Created : 2016-02-11
# * Authors : Benoit Michau 
# *--------------------------------------------------------
#*/
#
# All basic conversion function in native Python should be handled here
#
import sys
from struct   import pack, unpack
from binascii import hexlify, unhexlify
from types    import NoneType

# use gmpy for handling very large integers
try:
    from gmpy import mpz
except ImportError:
    try:
        from gmpy2 import mpz
    except ImportError:
        # just use Python large integer handling (which is slow)
        _WITH_MPZ = False
    else:
        _WITH_MPZ = True
        _MPZ_T = type(mpz(0))
else:
    _WITH_MPZ = True
    _MPZ_T = type(mpz(0))


#------------------------------------------------------------------------------#
# Python2 oddities
#------------------------------------------------------------------------------#
python_version = sys.version_info[0]

# Python2 has long type
if _WITH_MPZ:
    integer_types = (int, long, _MPZ_T)
else:
    integer_types = (int, long)
# str and bytes are similar in Python2
bytes_types = (str, )
# unicode is defined in Python2 and not in Python3
str_types = (str, unicode)
# NoneType imported from types

# defines bchr() identical to chr()
bchr = chr

#------------------------------------------------------------------------------#
# Pycrate generic error
#------------------------------------------------------------------------------#

class PycrateErr(Exception):
    pass

#------------------------------------------------------------------------------#
# bit list functions
#------------------------------------------------------------------------------#

ARRTOBIT_LUT = {
    0: (0, 0, 0, 0, 0, 0, 0, 0),
    1: (0, 0, 0, 0, 0, 0, 0, 1),
    2: (0, 0, 0, 0, 0, 0, 1, 0),
    3: (0, 0, 0, 0, 0, 0, 1, 1),
    4: (0, 0, 0, 0, 0, 1, 0, 0),
    5: (0, 0, 0, 0, 0, 1, 0, 1),
    6: (0, 0, 0, 0, 0, 1, 1, 0),
    7: (0, 0, 0, 0, 0, 1, 1, 1),
    8: (0, 0, 0, 0, 1, 0, 0, 0),
    9: (0, 0, 0, 0, 1, 0, 0, 1),
    10: (0, 0, 0, 0, 1, 0, 1, 0),
    11: (0, 0, 0, 0, 1, 0, 1, 1),
    12: (0, 0, 0, 0, 1, 1, 0, 0),
    13: (0, 0, 0, 0, 1, 1, 0, 1),
    14: (0, 0, 0, 0, 1, 1, 1, 0),
    15: (0, 0, 0, 0, 1, 1, 1, 1),
    16: (0, 0, 0, 1, 0, 0, 0, 0),
    17: (0, 0, 0, 1, 0, 0, 0, 1),
    18: (0, 0, 0, 1, 0, 0, 1, 0),
    19: (0, 0, 0, 1, 0, 0, 1, 1),
    20: (0, 0, 0, 1, 0, 1, 0, 0),
    21: (0, 0, 0, 1, 0, 1, 0, 1),
    22: (0, 0, 0, 1, 0, 1, 1, 0),
    23: (0, 0, 0, 1, 0, 1, 1, 1),
    24: (0, 0, 0, 1, 1, 0, 0, 0),
    25: (0, 0, 0, 1, 1, 0, 0, 1),
    26: (0, 0, 0, 1, 1, 0, 1, 0),
    27: (0, 0, 0, 1, 1, 0, 1, 1),
    28: (0, 0, 0, 1, 1, 1, 0, 0),
    29: (0, 0, 0, 1, 1, 1, 0, 1),
    30: (0, 0, 0, 1, 1, 1, 1, 0),
    31: (0, 0, 0, 1, 1, 1, 1, 1),
    32: (0, 0, 1, 0, 0, 0, 0, 0),
    33: (0, 0, 1, 0, 0, 0, 0, 1),
    34: (0, 0, 1, 0, 0, 0, 1, 0),
    35: (0, 0, 1, 0, 0, 0, 1, 1),
    36: (0, 0, 1, 0, 0, 1, 0, 0),
    37: (0, 0, 1, 0, 0, 1, 0, 1),
    38: (0, 0, 1, 0, 0, 1, 1, 0),
    39: (0, 0, 1, 0, 0, 1, 1, 1),
    40: (0, 0, 1, 0, 1, 0, 0, 0),
    41: (0, 0, 1, 0, 1, 0, 0, 1),
    42: (0, 0, 1, 0, 1, 0, 1, 0),
    43: (0, 0, 1, 0, 1, 0, 1, 1),
    44: (0, 0, 1, 0, 1, 1, 0, 0),
    45: (0, 0, 1, 0, 1, 1, 0, 1),
    46: (0, 0, 1, 0, 1, 1, 1, 0),
    47: (0, 0, 1, 0, 1, 1, 1, 1),
    48: (0, 0, 1, 1, 0, 0, 0, 0),
    49: (0, 0, 1, 1, 0, 0, 0, 1),
    50: (0, 0, 1, 1, 0, 0, 1, 0),
    51: (0, 0, 1, 1, 0, 0, 1, 1),
    52: (0, 0, 1, 1, 0, 1, 0, 0),
    53: (0, 0, 1, 1, 0, 1, 0, 1),
    54: (0, 0, 1, 1, 0, 1, 1, 0),
    55: (0, 0, 1, 1, 0, 1, 1, 1),
    56: (0, 0, 1, 1, 1, 0, 0, 0),
    57: (0, 0, 1, 1, 1, 0, 0, 1),
    58: (0, 0, 1, 1, 1, 0, 1, 0),
    59: (0, 0, 1, 1, 1, 0, 1, 1),
    60: (0, 0, 1, 1, 1, 1, 0, 0),
    61: (0, 0, 1, 1, 1, 1, 0, 1),
    62: (0, 0, 1, 1, 1, 1, 1, 0),
    63: (0, 0, 1, 1, 1, 1, 1, 1),
    64: (0, 1, 0, 0, 0, 0, 0, 0),
    65: (0, 1, 0, 0, 0, 0, 0, 1),
    66: (0, 1, 0, 0, 0, 0, 1, 0),
    67: (0, 1, 0, 0, 0, 0, 1, 1),
    68: (0, 1, 0, 0, 0, 1, 0, 0),
    69: (0, 1, 0, 0, 0, 1, 0, 1),
    70: (0, 1, 0, 0, 0, 1, 1, 0),
    71: (0, 1, 0, 0, 0, 1, 1, 1),
    72: (0, 1, 0, 0, 1, 0, 0, 0),
    73: (0, 1, 0, 0, 1, 0, 0, 1),
    74: (0, 1, 0, 0, 1, 0, 1, 0),
    75: (0, 1, 0, 0, 1, 0, 1, 1),
    76: (0, 1, 0, 0, 1, 1, 0, 0),
    77: (0, 1, 0, 0, 1, 1, 0, 1),
    78: (0, 1, 0, 0, 1, 1, 1, 0),
    79: (0, 1, 0, 0, 1, 1, 1, 1),
    80: (0, 1, 0, 1, 0, 0, 0, 0),
    81: (0, 1, 0, 1, 0, 0, 0, 1),
    82: (0, 1, 0, 1, 0, 0, 1, 0),
    83: (0, 1, 0, 1, 0, 0, 1, 1),
    84: (0, 1, 0, 1, 0, 1, 0, 0),
    85: (0, 1, 0, 1, 0, 1, 0, 1),
    86: (0, 1, 0, 1, 0, 1, 1, 0),
    87: (0, 1, 0, 1, 0, 1, 1, 1),
    88: (0, 1, 0, 1, 1, 0, 0, 0),
    89: (0, 1, 0, 1, 1, 0, 0, 1),
    90: (0, 1, 0, 1, 1, 0, 1, 0),
    91: (0, 1, 0, 1, 1, 0, 1, 1),
    92: (0, 1, 0, 1, 1, 1, 0, 0),
    93: (0, 1, 0, 1, 1, 1, 0, 1),
    94: (0, 1, 0, 1, 1, 1, 1, 0),
    95: (0, 1, 0, 1, 1, 1, 1, 1),
    96: (0, 1, 1, 0, 0, 0, 0, 0),
    97: (0, 1, 1, 0, 0, 0, 0, 1),
    98: (0, 1, 1, 0, 0, 0, 1, 0),
    99: (0, 1, 1, 0, 0, 0, 1, 1),
    100: (0, 1, 1, 0, 0, 1, 0, 0),
    101: (0, 1, 1, 0, 0, 1, 0, 1),
    102: (0, 1, 1, 0, 0, 1, 1, 0),
    103: (0, 1, 1, 0, 0, 1, 1, 1),
    104: (0, 1, 1, 0, 1, 0, 0, 0),
    105: (0, 1, 1, 0, 1, 0, 0, 1),
    106: (0, 1, 1, 0, 1, 0, 1, 0),
    107: (0, 1, 1, 0, 1, 0, 1, 1),
    108: (0, 1, 1, 0, 1, 1, 0, 0),
    109: (0, 1, 1, 0, 1, 1, 0, 1),
    110: (0, 1, 1, 0, 1, 1, 1, 0),
    111: (0, 1, 1, 0, 1, 1, 1, 1),
    112: (0, 1, 1, 1, 0, 0, 0, 0),
    113: (0, 1, 1, 1, 0, 0, 0, 1),
    114: (0, 1, 1, 1, 0, 0, 1, 0),
    115: (0, 1, 1, 1, 0, 0, 1, 1),
    116: (0, 1, 1, 1, 0, 1, 0, 0),
    117: (0, 1, 1, 1, 0, 1, 0, 1),
    118: (0, 1, 1, 1, 0, 1, 1, 0),
    119: (0, 1, 1, 1, 0, 1, 1, 1),
    120: (0, 1, 1, 1, 1, 0, 0, 0),
    121: (0, 1, 1, 1, 1, 0, 0, 1),
    122: (0, 1, 1, 1, 1, 0, 1, 0),
    123: (0, 1, 1, 1, 1, 0, 1, 1),
    124: (0, 1, 1, 1, 1, 1, 0, 0),
    125: (0, 1, 1, 1, 1, 1, 0, 1),
    126: (0, 1, 1, 1, 1, 1, 1, 0),
    127: (0, 1, 1, 1, 1, 1, 1, 1),
    128: (1, 0, 0, 0, 0, 0, 0, 0),
    129: (1, 0, 0, 0, 0, 0, 0, 1),
    130: (1, 0, 0, 0, 0, 0, 1, 0),
    131: (1, 0, 0, 0, 0, 0, 1, 1),
    132: (1, 0, 0, 0, 0, 1, 0, 0),
    133: (1, 0, 0, 0, 0, 1, 0, 1),
    134: (1, 0, 0, 0, 0, 1, 1, 0),
    135: (1, 0, 0, 0, 0, 1, 1, 1),
    136: (1, 0, 0, 0, 1, 0, 0, 0),
    137: (1, 0, 0, 0, 1, 0, 0, 1),
    138: (1, 0, 0, 0, 1, 0, 1, 0),
    139: (1, 0, 0, 0, 1, 0, 1, 1),
    140: (1, 0, 0, 0, 1, 1, 0, 0),
    141: (1, 0, 0, 0, 1, 1, 0, 1),
    142: (1, 0, 0, 0, 1, 1, 1, 0),
    143: (1, 0, 0, 0, 1, 1, 1, 1),
    144: (1, 0, 0, 1, 0, 0, 0, 0),
    145: (1, 0, 0, 1, 0, 0, 0, 1),
    146: (1, 0, 0, 1, 0, 0, 1, 0),
    147: (1, 0, 0, 1, 0, 0, 1, 1),
    148: (1, 0, 0, 1, 0, 1, 0, 0),
    149: (1, 0, 0, 1, 0, 1, 0, 1),
    150: (1, 0, 0, 1, 0, 1, 1, 0),
    151: (1, 0, 0, 1, 0, 1, 1, 1),
    152: (1, 0, 0, 1, 1, 0, 0, 0),
    153: (1, 0, 0, 1, 1, 0, 0, 1),
    154: (1, 0, 0, 1, 1, 0, 1, 0),
    155: (1, 0, 0, 1, 1, 0, 1, 1),
    156: (1, 0, 0, 1, 1, 1, 0, 0),
    157: (1, 0, 0, 1, 1, 1, 0, 1),
    158: (1, 0, 0, 1, 1, 1, 1, 0),
    159: (1, 0, 0, 1, 1, 1, 1, 1),
    160: (1, 0, 1, 0, 0, 0, 0, 0),
    161: (1, 0, 1, 0, 0, 0, 0, 1),
    162: (1, 0, 1, 0, 0, 0, 1, 0),
    163: (1, 0, 1, 0, 0, 0, 1, 1),
    164: (1, 0, 1, 0, 0, 1, 0, 0),
    165: (1, 0, 1, 0, 0, 1, 0, 1),
    166: (1, 0, 1, 0, 0, 1, 1, 0),
    167: (1, 0, 1, 0, 0, 1, 1, 1),
    168: (1, 0, 1, 0, 1, 0, 0, 0),
    169: (1, 0, 1, 0, 1, 0, 0, 1),
    170: (1, 0, 1, 0, 1, 0, 1, 0),
    171: (1, 0, 1, 0, 1, 0, 1, 1),
    172: (1, 0, 1, 0, 1, 1, 0, 0),
    173: (1, 0, 1, 0, 1, 1, 0, 1),
    174: (1, 0, 1, 0, 1, 1, 1, 0),
    175: (1, 0, 1, 0, 1, 1, 1, 1),
    176: (1, 0, 1, 1, 0, 0, 0, 0),
    177: (1, 0, 1, 1, 0, 0, 0, 1),
    178: (1, 0, 1, 1, 0, 0, 1, 0),
    179: (1, 0, 1, 1, 0, 0, 1, 1),
    180: (1, 0, 1, 1, 0, 1, 0, 0),
    181: (1, 0, 1, 1, 0, 1, 0, 1),
    182: (1, 0, 1, 1, 0, 1, 1, 0),
    183: (1, 0, 1, 1, 0, 1, 1, 1),
    184: (1, 0, 1, 1, 1, 0, 0, 0),
    185: (1, 0, 1, 1, 1, 0, 0, 1),
    186: (1, 0, 1, 1, 1, 0, 1, 0),
    187: (1, 0, 1, 1, 1, 0, 1, 1),
    188: (1, 0, 1, 1, 1, 1, 0, 0),
    189: (1, 0, 1, 1, 1, 1, 0, 1),
    190: (1, 0, 1, 1, 1, 1, 1, 0),
    191: (1, 0, 1, 1, 1, 1, 1, 1),
    192: (1, 1, 0, 0, 0, 0, 0, 0),
    193: (1, 1, 0, 0, 0, 0, 0, 1),
    194: (1, 1, 0, 0, 0, 0, 1, 0),
    195: (1, 1, 0, 0, 0, 0, 1, 1),
    196: (1, 1, 0, 0, 0, 1, 0, 0),
    197: (1, 1, 0, 0, 0, 1, 0, 1),
    198: (1, 1, 0, 0, 0, 1, 1, 0),
    199: (1, 1, 0, 0, 0, 1, 1, 1),
    200: (1, 1, 0, 0, 1, 0, 0, 0),
    201: (1, 1, 0, 0, 1, 0, 0, 1),
    202: (1, 1, 0, 0, 1, 0, 1, 0),
    203: (1, 1, 0, 0, 1, 0, 1, 1),
    204: (1, 1, 0, 0, 1, 1, 0, 0),
    205: (1, 1, 0, 0, 1, 1, 0, 1),
    206: (1, 1, 0, 0, 1, 1, 1, 0),
    207: (1, 1, 0, 0, 1, 1, 1, 1),
    208: (1, 1, 0, 1, 0, 0, 0, 0),
    209: (1, 1, 0, 1, 0, 0, 0, 1),
    210: (1, 1, 0, 1, 0, 0, 1, 0),
    211: (1, 1, 0, 1, 0, 0, 1, 1),
    212: (1, 1, 0, 1, 0, 1, 0, 0),
    213: (1, 1, 0, 1, 0, 1, 0, 1),
    214: (1, 1, 0, 1, 0, 1, 1, 0),
    215: (1, 1, 0, 1, 0, 1, 1, 1),
    216: (1, 1, 0, 1, 1, 0, 0, 0),
    217: (1, 1, 0, 1, 1, 0, 0, 1),
    218: (1, 1, 0, 1, 1, 0, 1, 0),
    219: (1, 1, 0, 1, 1, 0, 1, 1),
    220: (1, 1, 0, 1, 1, 1, 0, 0),
    221: (1, 1, 0, 1, 1, 1, 0, 1),
    222: (1, 1, 0, 1, 1, 1, 1, 0),
    223: (1, 1, 0, 1, 1, 1, 1, 1),
    224: (1, 1, 1, 0, 0, 0, 0, 0),
    225: (1, 1, 1, 0, 0, 0, 0, 1),
    226: (1, 1, 1, 0, 0, 0, 1, 0),
    227: (1, 1, 1, 0, 0, 0, 1, 1),
    228: (1, 1, 1, 0, 0, 1, 0, 0),
    229: (1, 1, 1, 0, 0, 1, 0, 1),
    230: (1, 1, 1, 0, 0, 1, 1, 0),
    231: (1, 1, 1, 0, 0, 1, 1, 1),
    232: (1, 1, 1, 0, 1, 0, 0, 0),
    233: (1, 1, 1, 0, 1, 0, 0, 1),
    234: (1, 1, 1, 0, 1, 0, 1, 0),
    235: (1, 1, 1, 0, 1, 0, 1, 1),
    236: (1, 1, 1, 0, 1, 1, 0, 0),
    237: (1, 1, 1, 0, 1, 1, 0, 1),
    238: (1, 1, 1, 0, 1, 1, 1, 0),
    239: (1, 1, 1, 0, 1, 1, 1, 1),
    240: (1, 1, 1, 1, 0, 0, 0, 0),
    241: (1, 1, 1, 1, 0, 0, 0, 1),
    242: (1, 1, 1, 1, 0, 0, 1, 0),
    243: (1, 1, 1, 1, 0, 0, 1, 1),
    244: (1, 1, 1, 1, 0, 1, 0, 0),
    245: (1, 1, 1, 1, 0, 1, 0, 1),
    246: (1, 1, 1, 1, 0, 1, 1, 0),
    247: (1, 1, 1, 1, 0, 1, 1, 1),
    248: (1, 1, 1, 1, 1, 0, 0, 0),
    249: (1, 1, 1, 1, 1, 0, 0, 1),
    250: (1, 1, 1, 1, 1, 0, 1, 0),
    251: (1, 1, 1, 1, 1, 0, 1, 1),
    252: (1, 1, 1, 1, 1, 1, 0, 0),
    253: (1, 1, 1, 1, 1, 1, 0, 1),
    254: (1, 1, 1, 1, 1, 1, 1, 0),
    255: (1, 1, 1, 1, 1, 1, 1, 1)
    }

BYTETOBIT_LUT = {
    b'\x00': (0, 0, 0, 0, 0, 0, 0, 0),
    b'\x01': (0, 0, 0, 0, 0, 0, 0, 1),
    b'\x02': (0, 0, 0, 0, 0, 0, 1, 0),
    b'\x03': (0, 0, 0, 0, 0, 0, 1, 1),
    b'\x04': (0, 0, 0, 0, 0, 1, 0, 0),
    b'\x05': (0, 0, 0, 0, 0, 1, 0, 1),
    b'\x06': (0, 0, 0, 0, 0, 1, 1, 0),
    b'\x07': (0, 0, 0, 0, 0, 1, 1, 1),
    b'\x08': (0, 0, 0, 0, 1, 0, 0, 0),
    b'\t': (0, 0, 0, 0, 1, 0, 0, 1),
    b'\n': (0, 0, 0, 0, 1, 0, 1, 0),
    b'\x0b': (0, 0, 0, 0, 1, 0, 1, 1),
    b'\x0c': (0, 0, 0, 0, 1, 1, 0, 0),
    b'\r': (0, 0, 0, 0, 1, 1, 0, 1),
    b'\x0e': (0, 0, 0, 0, 1, 1, 1, 0),
    b'\x0f': (0, 0, 0, 0, 1, 1, 1, 1),
    b'\x10': (0, 0, 0, 1, 0, 0, 0, 0),
    b'\x11': (0, 0, 0, 1, 0, 0, 0, 1),
    b'\x12': (0, 0, 0, 1, 0, 0, 1, 0),
    b'\x13': (0, 0, 0, 1, 0, 0, 1, 1),
    b'\x14': (0, 0, 0, 1, 0, 1, 0, 0),
    b'\x15': (0, 0, 0, 1, 0, 1, 0, 1),
    b'\x16': (0, 0, 0, 1, 0, 1, 1, 0),
    b'\x17': (0, 0, 0, 1, 0, 1, 1, 1),
    b'\x18': (0, 0, 0, 1, 1, 0, 0, 0),
    b'\x19': (0, 0, 0, 1, 1, 0, 0, 1),
    b'\x1a': (0, 0, 0, 1, 1, 0, 1, 0),
    b'\x1b': (0, 0, 0, 1, 1, 0, 1, 1),
    b'\x1c': (0, 0, 0, 1, 1, 1, 0, 0),
    b'\x1d': (0, 0, 0, 1, 1, 1, 0, 1),
    b'\x1e': (0, 0, 0, 1, 1, 1, 1, 0),
    b'\x1f': (0, 0, 0, 1, 1, 1, 1, 1),
    b' ': (0, 0, 1, 0, 0, 0, 0, 0),
    b'!': (0, 0, 1, 0, 0, 0, 0, 1),
    b'"': (0, 0, 1, 0, 0, 0, 1, 0),
    b'#': (0, 0, 1, 0, 0, 0, 1, 1),
    b'$': (0, 0, 1, 0, 0, 1, 0, 0),
    b'%': (0, 0, 1, 0, 0, 1, 0, 1),
    b'&': (0, 0, 1, 0, 0, 1, 1, 0),
    b"'": (0, 0, 1, 0, 0, 1, 1, 1),
    b'(': (0, 0, 1, 0, 1, 0, 0, 0),
    b')': (0, 0, 1, 0, 1, 0, 0, 1),
    b'*': (0, 0, 1, 0, 1, 0, 1, 0),
    b'+': (0, 0, 1, 0, 1, 0, 1, 1),
    b',': (0, 0, 1, 0, 1, 1, 0, 0),
    b'-': (0, 0, 1, 0, 1, 1, 0, 1),
    b'.': (0, 0, 1, 0, 1, 1, 1, 0),
    b'/': (0, 0, 1, 0, 1, 1, 1, 1),
    b'0': (0, 0, 1, 1, 0, 0, 0, 0),
    b'1': (0, 0, 1, 1, 0, 0, 0, 1),
    b'2': (0, 0, 1, 1, 0, 0, 1, 0),
    b'3': (0, 0, 1, 1, 0, 0, 1, 1),
    b'4': (0, 0, 1, 1, 0, 1, 0, 0),
    b'5': (0, 0, 1, 1, 0, 1, 0, 1),
    b'6': (0, 0, 1, 1, 0, 1, 1, 0),
    b'7': (0, 0, 1, 1, 0, 1, 1, 1),
    b'8': (0, 0, 1, 1, 1, 0, 0, 0),
    b'9': (0, 0, 1, 1, 1, 0, 0, 1),
    b':': (0, 0, 1, 1, 1, 0, 1, 0),
    b';': (0, 0, 1, 1, 1, 0, 1, 1),
    b'<': (0, 0, 1, 1, 1, 1, 0, 0),
    b'=': (0, 0, 1, 1, 1, 1, 0, 1),
    b'>': (0, 0, 1, 1, 1, 1, 1, 0),
    b'?': (0, 0, 1, 1, 1, 1, 1, 1),
    b'@': (0, 1, 0, 0, 0, 0, 0, 0),
    b'A': (0, 1, 0, 0, 0, 0, 0, 1),
    b'B': (0, 1, 0, 0, 0, 0, 1, 0),
    b'C': (0, 1, 0, 0, 0, 0, 1, 1),
    b'D': (0, 1, 0, 0, 0, 1, 0, 0),
    b'E': (0, 1, 0, 0, 0, 1, 0, 1),
    b'F': (0, 1, 0, 0, 0, 1, 1, 0),
    b'G': (0, 1, 0, 0, 0, 1, 1, 1),
    b'H': (0, 1, 0, 0, 1, 0, 0, 0),
    b'I': (0, 1, 0, 0, 1, 0, 0, 1),
    b'J': (0, 1, 0, 0, 1, 0, 1, 0),
    b'K': (0, 1, 0, 0, 1, 0, 1, 1),
    b'L': (0, 1, 0, 0, 1, 1, 0, 0),
    b'M': (0, 1, 0, 0, 1, 1, 0, 1),
    b'N': (0, 1, 0, 0, 1, 1, 1, 0),
    b'O': (0, 1, 0, 0, 1, 1, 1, 1),
    b'P': (0, 1, 0, 1, 0, 0, 0, 0),
    b'Q': (0, 1, 0, 1, 0, 0, 0, 1),
    b'R': (0, 1, 0, 1, 0, 0, 1, 0),
    b'S': (0, 1, 0, 1, 0, 0, 1, 1),
    b'T': (0, 1, 0, 1, 0, 1, 0, 0),
    b'U': (0, 1, 0, 1, 0, 1, 0, 1),
    b'V': (0, 1, 0, 1, 0, 1, 1, 0),
    b'W': (0, 1, 0, 1, 0, 1, 1, 1),
    b'X': (0, 1, 0, 1, 1, 0, 0, 0),
    b'Y': (0, 1, 0, 1, 1, 0, 0, 1),
    b'Z': (0, 1, 0, 1, 1, 0, 1, 0),
    b'[': (0, 1, 0, 1, 1, 0, 1, 1),
    b'\\': (0, 1, 0, 1, 1, 1, 0, 0),
    b']': (0, 1, 0, 1, 1, 1, 0, 1),
    b'^': (0, 1, 0, 1, 1, 1, 1, 0),
    b'_': (0, 1, 0, 1, 1, 1, 1, 1),
    b'`': (0, 1, 1, 0, 0, 0, 0, 0),
    b'a': (0, 1, 1, 0, 0, 0, 0, 1),
    b'b': (0, 1, 1, 0, 0, 0, 1, 0),
    b'c': (0, 1, 1, 0, 0, 0, 1, 1),
    b'd': (0, 1, 1, 0, 0, 1, 0, 0),
    b'e': (0, 1, 1, 0, 0, 1, 0, 1),
    b'f': (0, 1, 1, 0, 0, 1, 1, 0),
    b'g': (0, 1, 1, 0, 0, 1, 1, 1),
    b'h': (0, 1, 1, 0, 1, 0, 0, 0),
    b'i': (0, 1, 1, 0, 1, 0, 0, 1),
    b'j': (0, 1, 1, 0, 1, 0, 1, 0),
    b'k': (0, 1, 1, 0, 1, 0, 1, 1),
    b'l': (0, 1, 1, 0, 1, 1, 0, 0),
    b'm': (0, 1, 1, 0, 1, 1, 0, 1),
    b'n': (0, 1, 1, 0, 1, 1, 1, 0),
    b'o': (0, 1, 1, 0, 1, 1, 1, 1),
    b'p': (0, 1, 1, 1, 0, 0, 0, 0),
    b'q': (0, 1, 1, 1, 0, 0, 0, 1),
    b'r': (0, 1, 1, 1, 0, 0, 1, 0),
    b's': (0, 1, 1, 1, 0, 0, 1, 1),
    b't': (0, 1, 1, 1, 0, 1, 0, 0),
    b'u': (0, 1, 1, 1, 0, 1, 0, 1),
    b'v': (0, 1, 1, 1, 0, 1, 1, 0),
    b'w': (0, 1, 1, 1, 0, 1, 1, 1),
    b'x': (0, 1, 1, 1, 1, 0, 0, 0),
    b'y': (0, 1, 1, 1, 1, 0, 0, 1),
    b'z': (0, 1, 1, 1, 1, 0, 1, 0),
    b'{': (0, 1, 1, 1, 1, 0, 1, 1),
    b'|': (0, 1, 1, 1, 1, 1, 0, 0),
    b'}': (0, 1, 1, 1, 1, 1, 0, 1),
    b'~': (0, 1, 1, 1, 1, 1, 1, 0),
    b'\x7f': (0, 1, 1, 1, 1, 1, 1, 1),
    b'\x80': (1, 0, 0, 0, 0, 0, 0, 0),
    b'\x81': (1, 0, 0, 0, 0, 0, 0, 1),
    b'\x82': (1, 0, 0, 0, 0, 0, 1, 0),
    b'\x83': (1, 0, 0, 0, 0, 0, 1, 1),
    b'\x84': (1, 0, 0, 0, 0, 1, 0, 0),
    b'\x85': (1, 0, 0, 0, 0, 1, 0, 1),
    b'\x86': (1, 0, 0, 0, 0, 1, 1, 0),
    b'\x87': (1, 0, 0, 0, 0, 1, 1, 1),
    b'\x88': (1, 0, 0, 0, 1, 0, 0, 0),
    b'\x89': (1, 0, 0, 0, 1, 0, 0, 1),
    b'\x8a': (1, 0, 0, 0, 1, 0, 1, 0),
    b'\x8b': (1, 0, 0, 0, 1, 0, 1, 1),
    b'\x8c': (1, 0, 0, 0, 1, 1, 0, 0),
    b'\x8d': (1, 0, 0, 0, 1, 1, 0, 1),
    b'\x8e': (1, 0, 0, 0, 1, 1, 1, 0),
    b'\x8f': (1, 0, 0, 0, 1, 1, 1, 1),
    b'\x90': (1, 0, 0, 1, 0, 0, 0, 0),
    b'\x91': (1, 0, 0, 1, 0, 0, 0, 1),
    b'\x92': (1, 0, 0, 1, 0, 0, 1, 0),
    b'\x93': (1, 0, 0, 1, 0, 0, 1, 1),
    b'\x94': (1, 0, 0, 1, 0, 1, 0, 0),
    b'\x95': (1, 0, 0, 1, 0, 1, 0, 1),
    b'\x96': (1, 0, 0, 1, 0, 1, 1, 0),
    b'\x97': (1, 0, 0, 1, 0, 1, 1, 1),
    b'\x98': (1, 0, 0, 1, 1, 0, 0, 0),
    b'\x99': (1, 0, 0, 1, 1, 0, 0, 1),
    b'\x9a': (1, 0, 0, 1, 1, 0, 1, 0),
    b'\x9b': (1, 0, 0, 1, 1, 0, 1, 1),
    b'\x9c': (1, 0, 0, 1, 1, 1, 0, 0),
    b'\x9d': (1, 0, 0, 1, 1, 1, 0, 1),
    b'\x9e': (1, 0, 0, 1, 1, 1, 1, 0),
    b'\x9f': (1, 0, 0, 1, 1, 1, 1, 1),
    b'\xa0': (1, 0, 1, 0, 0, 0, 0, 0),
    b'\xa1': (1, 0, 1, 0, 0, 0, 0, 1),
    b'\xa2': (1, 0, 1, 0, 0, 0, 1, 0),
    b'\xa3': (1, 0, 1, 0, 0, 0, 1, 1),
    b'\xa4': (1, 0, 1, 0, 0, 1, 0, 0),
    b'\xa5': (1, 0, 1, 0, 0, 1, 0, 1),
    b'\xa6': (1, 0, 1, 0, 0, 1, 1, 0),
    b'\xa7': (1, 0, 1, 0, 0, 1, 1, 1),
    b'\xa8': (1, 0, 1, 0, 1, 0, 0, 0),
    b'\xa9': (1, 0, 1, 0, 1, 0, 0, 1),
    b'\xaa': (1, 0, 1, 0, 1, 0, 1, 0),
    b'\xab': (1, 0, 1, 0, 1, 0, 1, 1),
    b'\xac': (1, 0, 1, 0, 1, 1, 0, 0),
    b'\xad': (1, 0, 1, 0, 1, 1, 0, 1),
    b'\xae': (1, 0, 1, 0, 1, 1, 1, 0),
    b'\xaf': (1, 0, 1, 0, 1, 1, 1, 1),
    b'\xb0': (1, 0, 1, 1, 0, 0, 0, 0),
    b'\xb1': (1, 0, 1, 1, 0, 0, 0, 1),
    b'\xb2': (1, 0, 1, 1, 0, 0, 1, 0),
    b'\xb3': (1, 0, 1, 1, 0, 0, 1, 1),
    b'\xb4': (1, 0, 1, 1, 0, 1, 0, 0),
    b'\xb5': (1, 0, 1, 1, 0, 1, 0, 1),
    b'\xb6': (1, 0, 1, 1, 0, 1, 1, 0),
    b'\xb7': (1, 0, 1, 1, 0, 1, 1, 1),
    b'\xb8': (1, 0, 1, 1, 1, 0, 0, 0),
    b'\xb9': (1, 0, 1, 1, 1, 0, 0, 1),
    b'\xba': (1, 0, 1, 1, 1, 0, 1, 0),
    b'\xbb': (1, 0, 1, 1, 1, 0, 1, 1),
    b'\xbc': (1, 0, 1, 1, 1, 1, 0, 0),
    b'\xbd': (1, 0, 1, 1, 1, 1, 0, 1),
    b'\xbe': (1, 0, 1, 1, 1, 1, 1, 0),
    b'\xbf': (1, 0, 1, 1, 1, 1, 1, 1),
    b'\xc0': (1, 1, 0, 0, 0, 0, 0, 0),
    b'\xc1': (1, 1, 0, 0, 0, 0, 0, 1),
    b'\xc2': (1, 1, 0, 0, 0, 0, 1, 0),
    b'\xc3': (1, 1, 0, 0, 0, 0, 1, 1),
    b'\xc4': (1, 1, 0, 0, 0, 1, 0, 0),
    b'\xc5': (1, 1, 0, 0, 0, 1, 0, 1),
    b'\xc6': (1, 1, 0, 0, 0, 1, 1, 0),
    b'\xc7': (1, 1, 0, 0, 0, 1, 1, 1),
    b'\xc8': (1, 1, 0, 0, 1, 0, 0, 0),
    b'\xc9': (1, 1, 0, 0, 1, 0, 0, 1),
    b'\xca': (1, 1, 0, 0, 1, 0, 1, 0),
    b'\xcb': (1, 1, 0, 0, 1, 0, 1, 1),
    b'\xcc': (1, 1, 0, 0, 1, 1, 0, 0),
    b'\xcd': (1, 1, 0, 0, 1, 1, 0, 1),
    b'\xce': (1, 1, 0, 0, 1, 1, 1, 0),
    b'\xcf': (1, 1, 0, 0, 1, 1, 1, 1),
    b'\xd0': (1, 1, 0, 1, 0, 0, 0, 0),
    b'\xd1': (1, 1, 0, 1, 0, 0, 0, 1),
    b'\xd2': (1, 1, 0, 1, 0, 0, 1, 0),
    b'\xd3': (1, 1, 0, 1, 0, 0, 1, 1),
    b'\xd4': (1, 1, 0, 1, 0, 1, 0, 0),
    b'\xd5': (1, 1, 0, 1, 0, 1, 0, 1),
    b'\xd6': (1, 1, 0, 1, 0, 1, 1, 0),
    b'\xd7': (1, 1, 0, 1, 0, 1, 1, 1),
    b'\xd8': (1, 1, 0, 1, 1, 0, 0, 0),
    b'\xd9': (1, 1, 0, 1, 1, 0, 0, 1),
    b'\xda': (1, 1, 0, 1, 1, 0, 1, 0),
    b'\xdb': (1, 1, 0, 1, 1, 0, 1, 1),
    b'\xdc': (1, 1, 0, 1, 1, 1, 0, 0),
    b'\xdd': (1, 1, 0, 1, 1, 1, 0, 1),
    b'\xde': (1, 1, 0, 1, 1, 1, 1, 0),
    b'\xdf': (1, 1, 0, 1, 1, 1, 1, 1),
    b'\xe0': (1, 1, 1, 0, 0, 0, 0, 0),
    b'\xe1': (1, 1, 1, 0, 0, 0, 0, 1),
    b'\xe2': (1, 1, 1, 0, 0, 0, 1, 0),
    b'\xe3': (1, 1, 1, 0, 0, 0, 1, 1),
    b'\xe4': (1, 1, 1, 0, 0, 1, 0, 0),
    b'\xe5': (1, 1, 1, 0, 0, 1, 0, 1),
    b'\xe6': (1, 1, 1, 0, 0, 1, 1, 0),
    b'\xe7': (1, 1, 1, 0, 0, 1, 1, 1),
    b'\xe8': (1, 1, 1, 0, 1, 0, 0, 0),
    b'\xe9': (1, 1, 1, 0, 1, 0, 0, 1),
    b'\xea': (1, 1, 1, 0, 1, 0, 1, 0),
    b'\xeb': (1, 1, 1, 0, 1, 0, 1, 1),
    b'\xec': (1, 1, 1, 0, 1, 1, 0, 0),
    b'\xed': (1, 1, 1, 0, 1, 1, 0, 1),
    b'\xee': (1, 1, 1, 0, 1, 1, 1, 0),
    b'\xef': (1, 1, 1, 0, 1, 1, 1, 1),
    b'\xf0': (1, 1, 1, 1, 0, 0, 0, 0),
    b'\xf1': (1, 1, 1, 1, 0, 0, 0, 1),
    b'\xf2': (1, 1, 1, 1, 0, 0, 1, 0),
    b'\xf3': (1, 1, 1, 1, 0, 0, 1, 1),
    b'\xf4': (1, 1, 1, 1, 0, 1, 0, 0),
    b'\xf5': (1, 1, 1, 1, 0, 1, 0, 1),
    b'\xf6': (1, 1, 1, 1, 0, 1, 1, 0),
    b'\xf7': (1, 1, 1, 1, 0, 1, 1, 1),
    b'\xf8': (1, 1, 1, 1, 1, 0, 0, 0),
    b'\xf9': (1, 1, 1, 1, 1, 0, 0, 1),
    b'\xfa': (1, 1, 1, 1, 1, 0, 1, 0),
    b'\xfb': (1, 1, 1, 1, 1, 0, 1, 1),
    b'\xfc': (1, 1, 1, 1, 1, 1, 0, 0),
    b'\xfd': (1, 1, 1, 1, 1, 1, 0, 1),
    b'\xfe': (1, 1, 1, 1, 1, 1, 1, 0),
    b'\xff': (1, 1, 1, 1, 1, 1, 1, 1)
    }

BITTOARR_LUT = {
    (0, 0, 0, 0, 0, 0, 0, 0) : 0,
    (0, 0, 0, 0, 0, 0, 0, 1) : 1,
    (0, 0, 0, 0, 0, 0, 1, 0) : 2,
    (0, 0, 0, 0, 0, 0, 1, 1) : 3,
    (0, 0, 0, 0, 0, 1, 0, 0) : 4,
    (0, 0, 0, 0, 0, 1, 0, 1) : 5,
    (0, 0, 0, 0, 0, 1, 1, 0) : 6,
    (0, 0, 0, 0, 0, 1, 1, 1) : 7,
    (0, 0, 0, 0, 1, 0, 0, 0) : 8,
    (0, 0, 0, 0, 1, 0, 0, 1) : 9,
    (0, 0, 0, 0, 1, 0, 1, 0) : 10,
    (0, 0, 0, 0, 1, 0, 1, 1) : 11,
    (0, 0, 0, 0, 1, 1, 0, 0) : 12,
    (0, 0, 0, 0, 1, 1, 0, 1) : 13,
    (0, 0, 0, 0, 1, 1, 1, 0) : 14,
    (0, 0, 0, 0, 1, 1, 1, 1) : 15,
    (0, 0, 0, 1, 0, 0, 0, 0) : 16,
    (0, 0, 0, 1, 0, 0, 0, 1) : 17,
    (0, 0, 0, 1, 0, 0, 1, 0) : 18,
    (0, 0, 0, 1, 0, 0, 1, 1) : 19,
    (0, 0, 0, 1, 0, 1, 0, 0) : 20,
    (0, 0, 0, 1, 0, 1, 0, 1) : 21,
    (0, 0, 0, 1, 0, 1, 1, 0) : 22,
    (0, 0, 0, 1, 0, 1, 1, 1) : 23,
    (0, 0, 0, 1, 1, 0, 0, 0) : 24,
    (0, 0, 0, 1, 1, 0, 0, 1) : 25,
    (0, 0, 0, 1, 1, 0, 1, 0) : 26,
    (0, 0, 0, 1, 1, 0, 1, 1) : 27,
    (0, 0, 0, 1, 1, 1, 0, 0) : 28,
    (0, 0, 0, 1, 1, 1, 0, 1) : 29,
    (0, 0, 0, 1, 1, 1, 1, 0) : 30,
    (0, 0, 0, 1, 1, 1, 1, 1) : 31,
    (0, 0, 1, 0, 0, 0, 0, 0) : 32,
    (0, 0, 1, 0, 0, 0, 0, 1) : 33,
    (0, 0, 1, 0, 0, 0, 1, 0) : 34,
    (0, 0, 1, 0, 0, 0, 1, 1) : 35,
    (0, 0, 1, 0, 0, 1, 0, 0) : 36,
    (0, 0, 1, 0, 0, 1, 0, 1) : 37,
    (0, 0, 1, 0, 0, 1, 1, 0) : 38,
    (0, 0, 1, 0, 0, 1, 1, 1) : 39,
    (0, 0, 1, 0, 1, 0, 0, 0) : 40,
    (0, 0, 1, 0, 1, 0, 0, 1) : 41,
    (0, 0, 1, 0, 1, 0, 1, 0) : 42,
    (0, 0, 1, 0, 1, 0, 1, 1) : 43,
    (0, 0, 1, 0, 1, 1, 0, 0) : 44,
    (0, 0, 1, 0, 1, 1, 0, 1) : 45,
    (0, 0, 1, 0, 1, 1, 1, 0) : 46,
    (0, 0, 1, 0, 1, 1, 1, 1) : 47,
    (0, 0, 1, 1, 0, 0, 0, 0) : 48,
    (0, 0, 1, 1, 0, 0, 0, 1) : 49,
    (0, 0, 1, 1, 0, 0, 1, 0) : 50,
    (0, 0, 1, 1, 0, 0, 1, 1) : 51,
    (0, 0, 1, 1, 0, 1, 0, 0) : 52,
    (0, 0, 1, 1, 0, 1, 0, 1) : 53,
    (0, 0, 1, 1, 0, 1, 1, 0) : 54,
    (0, 0, 1, 1, 0, 1, 1, 1) : 55,
    (0, 0, 1, 1, 1, 0, 0, 0) : 56,
    (0, 0, 1, 1, 1, 0, 0, 1) : 57,
    (0, 0, 1, 1, 1, 0, 1, 0) : 58,
    (0, 0, 1, 1, 1, 0, 1, 1) : 59,
    (0, 0, 1, 1, 1, 1, 0, 0) : 60,
    (0, 0, 1, 1, 1, 1, 0, 1) : 61,
    (0, 0, 1, 1, 1, 1, 1, 0) : 62,
    (0, 0, 1, 1, 1, 1, 1, 1) : 63,
    (0, 1, 0, 0, 0, 0, 0, 0) : 64,
    (0, 1, 0, 0, 0, 0, 0, 1) : 65,
    (0, 1, 0, 0, 0, 0, 1, 0) : 66,
    (0, 1, 0, 0, 0, 0, 1, 1) : 67,
    (0, 1, 0, 0, 0, 1, 0, 0) : 68,
    (0, 1, 0, 0, 0, 1, 0, 1) : 69,
    (0, 1, 0, 0, 0, 1, 1, 0) : 70,
    (0, 1, 0, 0, 0, 1, 1, 1) : 71,
    (0, 1, 0, 0, 1, 0, 0, 0) : 72,
    (0, 1, 0, 0, 1, 0, 0, 1) : 73,
    (0, 1, 0, 0, 1, 0, 1, 0) : 74,
    (0, 1, 0, 0, 1, 0, 1, 1) : 75,
    (0, 1, 0, 0, 1, 1, 0, 0) : 76,
    (0, 1, 0, 0, 1, 1, 0, 1) : 77,
    (0, 1, 0, 0, 1, 1, 1, 0) : 78,
    (0, 1, 0, 0, 1, 1, 1, 1) : 79,
    (0, 1, 0, 1, 0, 0, 0, 0) : 80,
    (0, 1, 0, 1, 0, 0, 0, 1) : 81,
    (0, 1, 0, 1, 0, 0, 1, 0) : 82,
    (0, 1, 0, 1, 0, 0, 1, 1) : 83,
    (0, 1, 0, 1, 0, 1, 0, 0) : 84,
    (0, 1, 0, 1, 0, 1, 0, 1) : 85,
    (0, 1, 0, 1, 0, 1, 1, 0) : 86,
    (0, 1, 0, 1, 0, 1, 1, 1) : 87,
    (0, 1, 0, 1, 1, 0, 0, 0) : 88,
    (0, 1, 0, 1, 1, 0, 0, 1) : 89,
    (0, 1, 0, 1, 1, 0, 1, 0) : 90,
    (0, 1, 0, 1, 1, 0, 1, 1) : 91,
    (0, 1, 0, 1, 1, 1, 0, 0) : 92,
    (0, 1, 0, 1, 1, 1, 0, 1) : 93,
    (0, 1, 0, 1, 1, 1, 1, 0) : 94,
    (0, 1, 0, 1, 1, 1, 1, 1) : 95,
    (0, 1, 1, 0, 0, 0, 0, 0) : 96,
    (0, 1, 1, 0, 0, 0, 0, 1) : 97,
    (0, 1, 1, 0, 0, 0, 1, 0) : 98,
    (0, 1, 1, 0, 0, 0, 1, 1) : 99,
    (0, 1, 1, 0, 0, 1, 0, 0) : 100,
    (0, 1, 1, 0, 0, 1, 0, 1) : 101,
    (0, 1, 1, 0, 0, 1, 1, 0) : 102,
    (0, 1, 1, 0, 0, 1, 1, 1) : 103,
    (0, 1, 1, 0, 1, 0, 0, 0) : 104,
    (0, 1, 1, 0, 1, 0, 0, 1) : 105,
    (0, 1, 1, 0, 1, 0, 1, 0) : 106,
    (0, 1, 1, 0, 1, 0, 1, 1) : 107,
    (0, 1, 1, 0, 1, 1, 0, 0) : 108,
    (0, 1, 1, 0, 1, 1, 0, 1) : 109,
    (0, 1, 1, 0, 1, 1, 1, 0) : 110,
    (0, 1, 1, 0, 1, 1, 1, 1) : 111,
    (0, 1, 1, 1, 0, 0, 0, 0) : 112,
    (0, 1, 1, 1, 0, 0, 0, 1) : 113,
    (0, 1, 1, 1, 0, 0, 1, 0) : 114,
    (0, 1, 1, 1, 0, 0, 1, 1) : 115,
    (0, 1, 1, 1, 0, 1, 0, 0) : 116,
    (0, 1, 1, 1, 0, 1, 0, 1) : 117,
    (0, 1, 1, 1, 0, 1, 1, 0) : 118,
    (0, 1, 1, 1, 0, 1, 1, 1) : 119,
    (0, 1, 1, 1, 1, 0, 0, 0) : 120,
    (0, 1, 1, 1, 1, 0, 0, 1) : 121,
    (0, 1, 1, 1, 1, 0, 1, 0) : 122,
    (0, 1, 1, 1, 1, 0, 1, 1) : 123,
    (0, 1, 1, 1, 1, 1, 0, 0) : 124,
    (0, 1, 1, 1, 1, 1, 0, 1) : 125,
    (0, 1, 1, 1, 1, 1, 1, 0) : 126,
    (0, 1, 1, 1, 1, 1, 1, 1) : 127,
    (1, 0, 0, 0, 0, 0, 0, 0) : 128,
    (1, 0, 0, 0, 0, 0, 0, 1) : 129,
    (1, 0, 0, 0, 0, 0, 1, 0) : 130,
    (1, 0, 0, 0, 0, 0, 1, 1) : 131,
    (1, 0, 0, 0, 0, 1, 0, 0) : 132,
    (1, 0, 0, 0, 0, 1, 0, 1) : 133,
    (1, 0, 0, 0, 0, 1, 1, 0) : 134,
    (1, 0, 0, 0, 0, 1, 1, 1) : 135,
    (1, 0, 0, 0, 1, 0, 0, 0) : 136,
    (1, 0, 0, 0, 1, 0, 0, 1) : 137,
    (1, 0, 0, 0, 1, 0, 1, 0) : 138,
    (1, 0, 0, 0, 1, 0, 1, 1) : 139,
    (1, 0, 0, 0, 1, 1, 0, 0) : 140,
    (1, 0, 0, 0, 1, 1, 0, 1) : 141,
    (1, 0, 0, 0, 1, 1, 1, 0) : 142,
    (1, 0, 0, 0, 1, 1, 1, 1) : 143,
    (1, 0, 0, 1, 0, 0, 0, 0) : 144,
    (1, 0, 0, 1, 0, 0, 0, 1) : 145,
    (1, 0, 0, 1, 0, 0, 1, 0) : 146,
    (1, 0, 0, 1, 0, 0, 1, 1) : 147,
    (1, 0, 0, 1, 0, 1, 0, 0) : 148,
    (1, 0, 0, 1, 0, 1, 0, 1) : 149,
    (1, 0, 0, 1, 0, 1, 1, 0) : 150,
    (1, 0, 0, 1, 0, 1, 1, 1) : 151,
    (1, 0, 0, 1, 1, 0, 0, 0) : 152,
    (1, 0, 0, 1, 1, 0, 0, 1) : 153,
    (1, 0, 0, 1, 1, 0, 1, 0) : 154,
    (1, 0, 0, 1, 1, 0, 1, 1) : 155,
    (1, 0, 0, 1, 1, 1, 0, 0) : 156,
    (1, 0, 0, 1, 1, 1, 0, 1) : 157,
    (1, 0, 0, 1, 1, 1, 1, 0) : 158,
    (1, 0, 0, 1, 1, 1, 1, 1) : 159,
    (1, 0, 1, 0, 0, 0, 0, 0) : 160,
    (1, 0, 1, 0, 0, 0, 0, 1) : 161,
    (1, 0, 1, 0, 0, 0, 1, 0) : 162,
    (1, 0, 1, 0, 0, 0, 1, 1) : 163,
    (1, 0, 1, 0, 0, 1, 0, 0) : 164,
    (1, 0, 1, 0, 0, 1, 0, 1) : 165,
    (1, 0, 1, 0, 0, 1, 1, 0) : 166,
    (1, 0, 1, 0, 0, 1, 1, 1) : 167,
    (1, 0, 1, 0, 1, 0, 0, 0) : 168,
    (1, 0, 1, 0, 1, 0, 0, 1) : 169,
    (1, 0, 1, 0, 1, 0, 1, 0) : 170,
    (1, 0, 1, 0, 1, 0, 1, 1) : 171,
    (1, 0, 1, 0, 1, 1, 0, 0) : 172,
    (1, 0, 1, 0, 1, 1, 0, 1) : 173,
    (1, 0, 1, 0, 1, 1, 1, 0) : 174,
    (1, 0, 1, 0, 1, 1, 1, 1) : 175,
    (1, 0, 1, 1, 0, 0, 0, 0) : 176,
    (1, 0, 1, 1, 0, 0, 0, 1) : 177,
    (1, 0, 1, 1, 0, 0, 1, 0) : 178,
    (1, 0, 1, 1, 0, 0, 1, 1) : 179,
    (1, 0, 1, 1, 0, 1, 0, 0) : 180,
    (1, 0, 1, 1, 0, 1, 0, 1) : 181,
    (1, 0, 1, 1, 0, 1, 1, 0) : 182,
    (1, 0, 1, 1, 0, 1, 1, 1) : 183,
    (1, 0, 1, 1, 1, 0, 0, 0) : 184,
    (1, 0, 1, 1, 1, 0, 0, 1) : 185,
    (1, 0, 1, 1, 1, 0, 1, 0) : 186,
    (1, 0, 1, 1, 1, 0, 1, 1) : 187,
    (1, 0, 1, 1, 1, 1, 0, 0) : 188,
    (1, 0, 1, 1, 1, 1, 0, 1) : 189,
    (1, 0, 1, 1, 1, 1, 1, 0) : 190,
    (1, 0, 1, 1, 1, 1, 1, 1) : 191,
    (1, 1, 0, 0, 0, 0, 0, 0) : 192,
    (1, 1, 0, 0, 0, 0, 0, 1) : 193,
    (1, 1, 0, 0, 0, 0, 1, 0) : 194,
    (1, 1, 0, 0, 0, 0, 1, 1) : 195,
    (1, 1, 0, 0, 0, 1, 0, 0) : 196,
    (1, 1, 0, 0, 0, 1, 0, 1) : 197,
    (1, 1, 0, 0, 0, 1, 1, 0) : 198,
    (1, 1, 0, 0, 0, 1, 1, 1) : 199,
    (1, 1, 0, 0, 1, 0, 0, 0) : 200,
    (1, 1, 0, 0, 1, 0, 0, 1) : 201,
    (1, 1, 0, 0, 1, 0, 1, 0) : 202,
    (1, 1, 0, 0, 1, 0, 1, 1) : 203,
    (1, 1, 0, 0, 1, 1, 0, 0) : 204,
    (1, 1, 0, 0, 1, 1, 0, 1) : 205,
    (1, 1, 0, 0, 1, 1, 1, 0) : 206,
    (1, 1, 0, 0, 1, 1, 1, 1) : 207,
    (1, 1, 0, 1, 0, 0, 0, 0) : 208,
    (1, 1, 0, 1, 0, 0, 0, 1) : 209,
    (1, 1, 0, 1, 0, 0, 1, 0) : 210,
    (1, 1, 0, 1, 0, 0, 1, 1) : 211,
    (1, 1, 0, 1, 0, 1, 0, 0) : 212,
    (1, 1, 0, 1, 0, 1, 0, 1) : 213,
    (1, 1, 0, 1, 0, 1, 1, 0) : 214,
    (1, 1, 0, 1, 0, 1, 1, 1) : 215,
    (1, 1, 0, 1, 1, 0, 0, 0) : 216,
    (1, 1, 0, 1, 1, 0, 0, 1) : 217,
    (1, 1, 0, 1, 1, 0, 1, 0) : 218,
    (1, 1, 0, 1, 1, 0, 1, 1) : 219,
    (1, 1, 0, 1, 1, 1, 0, 0) : 220,
    (1, 1, 0, 1, 1, 1, 0, 1) : 221,
    (1, 1, 0, 1, 1, 1, 1, 0) : 222,
    (1, 1, 0, 1, 1, 1, 1, 1) : 223,
    (1, 1, 1, 0, 0, 0, 0, 0) : 224,
    (1, 1, 1, 0, 0, 0, 0, 1) : 225,
    (1, 1, 1, 0, 0, 0, 1, 0) : 226,
    (1, 1, 1, 0, 0, 0, 1, 1) : 227,
    (1, 1, 1, 0, 0, 1, 0, 0) : 228,
    (1, 1, 1, 0, 0, 1, 0, 1) : 229,
    (1, 1, 1, 0, 0, 1, 1, 0) : 230,
    (1, 1, 1, 0, 0, 1, 1, 1) : 231,
    (1, 1, 1, 0, 1, 0, 0, 0) : 232,
    (1, 1, 1, 0, 1, 0, 0, 1) : 233,
    (1, 1, 1, 0, 1, 0, 1, 0) : 234,
    (1, 1, 1, 0, 1, 0, 1, 1) : 235,
    (1, 1, 1, 0, 1, 1, 0, 0) : 236,
    (1, 1, 1, 0, 1, 1, 0, 1) : 237,
    (1, 1, 1, 0, 1, 1, 1, 0) : 238,
    (1, 1, 1, 0, 1, 1, 1, 1) : 239,
    (1, 1, 1, 1, 0, 0, 0, 0) : 240,
    (1, 1, 1, 1, 0, 0, 0, 1) : 241,
    (1, 1, 1, 1, 0, 0, 1, 0) : 242,
    (1, 1, 1, 1, 0, 0, 1, 1) : 243,
    (1, 1, 1, 1, 0, 1, 0, 0) : 244,
    (1, 1, 1, 1, 0, 1, 0, 1) : 245,
    (1, 1, 1, 1, 0, 1, 1, 0) : 246,
    (1, 1, 1, 1, 0, 1, 1, 1) : 247,
    (1, 1, 1, 1, 1, 0, 0, 0) : 248,
    (1, 1, 1, 1, 1, 0, 0, 1) : 249,
    (1, 1, 1, 1, 1, 0, 1, 0) : 250,
    (1, 1, 1, 1, 1, 0, 1, 1) : 251,
    (1, 1, 1, 1, 1, 1, 0, 0) : 252,
    (1, 1, 1, 1, 1, 1, 0, 1) : 253,
    (1, 1, 1, 1, 1, 1, 1, 0) : 254,
    (1, 1, 1, 1, 1, 1, 1, 1) : 255
    }

BITTOBYTE_LUT = {
    (0, 0, 0, 0, 0, 0, 0, 0): b'\x00',
    (0, 0, 0, 0, 0, 0, 0, 1): b'\x01',
    (0, 0, 0, 0, 0, 0, 1, 0): b'\x02',
    (0, 0, 0, 0, 0, 0, 1, 1): b'\x03',
    (0, 0, 0, 0, 0, 1, 0, 0): b'\x04',
    (0, 0, 0, 0, 0, 1, 0, 1): b'\x05',
    (0, 0, 0, 0, 0, 1, 1, 0): b'\x06',
    (0, 0, 0, 0, 0, 1, 1, 1): b'\x07',
    (0, 0, 0, 0, 1, 0, 0, 0): b'\x08',
    (0, 0, 0, 0, 1, 0, 0, 1): b'\t',
    (0, 0, 0, 0, 1, 0, 1, 0): b'\n',
    (0, 0, 0, 0, 1, 0, 1, 1): b'\x0b',
    (0, 0, 0, 0, 1, 1, 0, 0): b'\x0c',
    (0, 0, 0, 0, 1, 1, 0, 1): b'\r',
    (0, 0, 0, 0, 1, 1, 1, 0): b'\x0e',
    (0, 0, 0, 0, 1, 1, 1, 1): b'\x0f',
    (0, 0, 0, 1, 0, 0, 0, 0): b'\x10',
    (0, 0, 0, 1, 0, 0, 0, 1): b'\x11',
    (0, 0, 0, 1, 0, 0, 1, 0): b'\x12',
    (0, 0, 0, 1, 0, 0, 1, 1): b'\x13',
    (0, 0, 0, 1, 0, 1, 0, 0): b'\x14',
    (0, 0, 0, 1, 0, 1, 0, 1): b'\x15',
    (0, 0, 0, 1, 0, 1, 1, 0): b'\x16',
    (0, 0, 0, 1, 0, 1, 1, 1): b'\x17',
    (0, 0, 0, 1, 1, 0, 0, 0): b'\x18',
    (0, 0, 0, 1, 1, 0, 0, 1): b'\x19',
    (0, 0, 0, 1, 1, 0, 1, 0): b'\x1a',
    (0, 0, 0, 1, 1, 0, 1, 1): b'\x1b',
    (0, 0, 0, 1, 1, 1, 0, 0): b'\x1c',
    (0, 0, 0, 1, 1, 1, 0, 1): b'\x1d',
    (0, 0, 0, 1, 1, 1, 1, 0): b'\x1e',
    (0, 0, 0, 1, 1, 1, 1, 1): b'\x1f',
    (0, 0, 1, 0, 0, 0, 0, 0): b' ',
    (0, 0, 1, 0, 0, 0, 0, 1): b'!',
    (0, 0, 1, 0, 0, 0, 1, 0): b'"',
    (0, 0, 1, 0, 0, 0, 1, 1): b'#',
    (0, 0, 1, 0, 0, 1, 0, 0): b'$',
    (0, 0, 1, 0, 0, 1, 0, 1): b'%',
    (0, 0, 1, 0, 0, 1, 1, 0): b'&',
    (0, 0, 1, 0, 0, 1, 1, 1): b"'",
    (0, 0, 1, 0, 1, 0, 0, 0): b'(',
    (0, 0, 1, 0, 1, 0, 0, 1): b')',
    (0, 0, 1, 0, 1, 0, 1, 0): b'*',
    (0, 0, 1, 0, 1, 0, 1, 1): b'+',
    (0, 0, 1, 0, 1, 1, 0, 0): b',',
    (0, 0, 1, 0, 1, 1, 0, 1): b'-',
    (0, 0, 1, 0, 1, 1, 1, 0): b'.',
    (0, 0, 1, 0, 1, 1, 1, 1): b'/',
    (0, 0, 1, 1, 0, 0, 0, 0): b'0',
    (0, 0, 1, 1, 0, 0, 0, 1): b'1',
    (0, 0, 1, 1, 0, 0, 1, 0): b'2',
    (0, 0, 1, 1, 0, 0, 1, 1): b'3',
    (0, 0, 1, 1, 0, 1, 0, 0): b'4',
    (0, 0, 1, 1, 0, 1, 0, 1): b'5',
    (0, 0, 1, 1, 0, 1, 1, 0): b'6',
    (0, 0, 1, 1, 0, 1, 1, 1): b'7',
    (0, 0, 1, 1, 1, 0, 0, 0): b'8',
    (0, 0, 1, 1, 1, 0, 0, 1): b'9',
    (0, 0, 1, 1, 1, 0, 1, 0): b':',
    (0, 0, 1, 1, 1, 0, 1, 1): b';',
    (0, 0, 1, 1, 1, 1, 0, 0): b'<',
    (0, 0, 1, 1, 1, 1, 0, 1): b'=',
    (0, 0, 1, 1, 1, 1, 1, 0): b'>',
    (0, 0, 1, 1, 1, 1, 1, 1): b'?',
    (0, 1, 0, 0, 0, 0, 0, 0): b'@',
    (0, 1, 0, 0, 0, 0, 0, 1): b'A',
    (0, 1, 0, 0, 0, 0, 1, 0): b'B',
    (0, 1, 0, 0, 0, 0, 1, 1): b'C',
    (0, 1, 0, 0, 0, 1, 0, 0): b'D',
    (0, 1, 0, 0, 0, 1, 0, 1): b'E',
    (0, 1, 0, 0, 0, 1, 1, 0): b'F',
    (0, 1, 0, 0, 0, 1, 1, 1): b'G',
    (0, 1, 0, 0, 1, 0, 0, 0): b'H',
    (0, 1, 0, 0, 1, 0, 0, 1): b'I',
    (0, 1, 0, 0, 1, 0, 1, 0): b'J',
    (0, 1, 0, 0, 1, 0, 1, 1): b'K',
    (0, 1, 0, 0, 1, 1, 0, 0): b'L',
    (0, 1, 0, 0, 1, 1, 0, 1): b'M',
    (0, 1, 0, 0, 1, 1, 1, 0): b'N',
    (0, 1, 0, 0, 1, 1, 1, 1): b'O',
    (0, 1, 0, 1, 0, 0, 0, 0): b'P',
    (0, 1, 0, 1, 0, 0, 0, 1): b'Q',
    (0, 1, 0, 1, 0, 0, 1, 0): b'R',
    (0, 1, 0, 1, 0, 0, 1, 1): b'S',
    (0, 1, 0, 1, 0, 1, 0, 0): b'T',
    (0, 1, 0, 1, 0, 1, 0, 1): b'U',
    (0, 1, 0, 1, 0, 1, 1, 0): b'V',
    (0, 1, 0, 1, 0, 1, 1, 1): b'W',
    (0, 1, 0, 1, 1, 0, 0, 0): b'X',
    (0, 1, 0, 1, 1, 0, 0, 1): b'Y',
    (0, 1, 0, 1, 1, 0, 1, 0): b'Z',
    (0, 1, 0, 1, 1, 0, 1, 1): b'[',
    (0, 1, 0, 1, 1, 1, 0, 0): b'\\',
    (0, 1, 0, 1, 1, 1, 0, 1): b']',
    (0, 1, 0, 1, 1, 1, 1, 0): b'^',
    (0, 1, 0, 1, 1, 1, 1, 1): b'_',
    (0, 1, 1, 0, 0, 0, 0, 0): b'`',
    (0, 1, 1, 0, 0, 0, 0, 1): b'a',
    (0, 1, 1, 0, 0, 0, 1, 0): b'b',
    (0, 1, 1, 0, 0, 0, 1, 1): b'c',
    (0, 1, 1, 0, 0, 1, 0, 0): b'd',
    (0, 1, 1, 0, 0, 1, 0, 1): b'e',
    (0, 1, 1, 0, 0, 1, 1, 0): b'f',
    (0, 1, 1, 0, 0, 1, 1, 1): b'g',
    (0, 1, 1, 0, 1, 0, 0, 0): b'h',
    (0, 1, 1, 0, 1, 0, 0, 1): b'i',
    (0, 1, 1, 0, 1, 0, 1, 0): b'j',
    (0, 1, 1, 0, 1, 0, 1, 1): b'k',
    (0, 1, 1, 0, 1, 1, 0, 0): b'l',
    (0, 1, 1, 0, 1, 1, 0, 1): b'm',
    (0, 1, 1, 0, 1, 1, 1, 0): b'n',
    (0, 1, 1, 0, 1, 1, 1, 1): b'o',
    (0, 1, 1, 1, 0, 0, 0, 0): b'p',
    (0, 1, 1, 1, 0, 0, 0, 1): b'q',
    (0, 1, 1, 1, 0, 0, 1, 0): b'r',
    (0, 1, 1, 1, 0, 0, 1, 1): b's',
    (0, 1, 1, 1, 0, 1, 0, 0): b't',
    (0, 1, 1, 1, 0, 1, 0, 1): b'u',
    (0, 1, 1, 1, 0, 1, 1, 0): b'v',
    (0, 1, 1, 1, 0, 1, 1, 1): b'w',
    (0, 1, 1, 1, 1, 0, 0, 0): b'x',
    (0, 1, 1, 1, 1, 0, 0, 1): b'y',
    (0, 1, 1, 1, 1, 0, 1, 0): b'z',
    (0, 1, 1, 1, 1, 0, 1, 1): b'{',
    (0, 1, 1, 1, 1, 1, 0, 0): b'|',
    (0, 1, 1, 1, 1, 1, 0, 1): b'}',
    (0, 1, 1, 1, 1, 1, 1, 0): b'~',
    (0, 1, 1, 1, 1, 1, 1, 1): b'\x7f',
    (1, 0, 0, 0, 0, 0, 0, 0): b'\x80',
    (1, 0, 0, 0, 0, 0, 0, 1): b'\x81',
    (1, 0, 0, 0, 0, 0, 1, 0): b'\x82',
    (1, 0, 0, 0, 0, 0, 1, 1): b'\x83',
    (1, 0, 0, 0, 0, 1, 0, 0): b'\x84',
    (1, 0, 0, 0, 0, 1, 0, 1): b'\x85',
    (1, 0, 0, 0, 0, 1, 1, 0): b'\x86',
    (1, 0, 0, 0, 0, 1, 1, 1): b'\x87',
    (1, 0, 0, 0, 1, 0, 0, 0): b'\x88',
    (1, 0, 0, 0, 1, 0, 0, 1): b'\x89',
    (1, 0, 0, 0, 1, 0, 1, 0): b'\x8a',
    (1, 0, 0, 0, 1, 0, 1, 1): b'\x8b',
    (1, 0, 0, 0, 1, 1, 0, 0): b'\x8c',
    (1, 0, 0, 0, 1, 1, 0, 1): b'\x8d',
    (1, 0, 0, 0, 1, 1, 1, 0): b'\x8e',
    (1, 0, 0, 0, 1, 1, 1, 1): b'\x8f',
    (1, 0, 0, 1, 0, 0, 0, 0): b'\x90',
    (1, 0, 0, 1, 0, 0, 0, 1): b'\x91',
    (1, 0, 0, 1, 0, 0, 1, 0): b'\x92',
    (1, 0, 0, 1, 0, 0, 1, 1): b'\x93',
    (1, 0, 0, 1, 0, 1, 0, 0): b'\x94',
    (1, 0, 0, 1, 0, 1, 0, 1): b'\x95',
    (1, 0, 0, 1, 0, 1, 1, 0): b'\x96',
    (1, 0, 0, 1, 0, 1, 1, 1): b'\x97',
    (1, 0, 0, 1, 1, 0, 0, 0): b'\x98',
    (1, 0, 0, 1, 1, 0, 0, 1): b'\x99',
    (1, 0, 0, 1, 1, 0, 1, 0): b'\x9a',
    (1, 0, 0, 1, 1, 0, 1, 1): b'\x9b',
    (1, 0, 0, 1, 1, 1, 0, 0): b'\x9c',
    (1, 0, 0, 1, 1, 1, 0, 1): b'\x9d',
    (1, 0, 0, 1, 1, 1, 1, 0): b'\x9e',
    (1, 0, 0, 1, 1, 1, 1, 1): b'\x9f',
    (1, 0, 1, 0, 0, 0, 0, 0): b'\xa0',
    (1, 0, 1, 0, 0, 0, 0, 1): b'\xa1',
    (1, 0, 1, 0, 0, 0, 1, 0): b'\xa2',
    (1, 0, 1, 0, 0, 0, 1, 1): b'\xa3',
    (1, 0, 1, 0, 0, 1, 0, 0): b'\xa4',
    (1, 0, 1, 0, 0, 1, 0, 1): b'\xa5',
    (1, 0, 1, 0, 0, 1, 1, 0): b'\xa6',
    (1, 0, 1, 0, 0, 1, 1, 1): b'\xa7',
    (1, 0, 1, 0, 1, 0, 0, 0): b'\xa8',
    (1, 0, 1, 0, 1, 0, 0, 1): b'\xa9',
    (1, 0, 1, 0, 1, 0, 1, 0): b'\xaa',
    (1, 0, 1, 0, 1, 0, 1, 1): b'\xab',
    (1, 0, 1, 0, 1, 1, 0, 0): b'\xac',
    (1, 0, 1, 0, 1, 1, 0, 1): b'\xad',
    (1, 0, 1, 0, 1, 1, 1, 0): b'\xae',
    (1, 0, 1, 0, 1, 1, 1, 1): b'\xaf',
    (1, 0, 1, 1, 0, 0, 0, 0): b'\xb0',
    (1, 0, 1, 1, 0, 0, 0, 1): b'\xb1',
    (1, 0, 1, 1, 0, 0, 1, 0): b'\xb2',
    (1, 0, 1, 1, 0, 0, 1, 1): b'\xb3',
    (1, 0, 1, 1, 0, 1, 0, 0): b'\xb4',
    (1, 0, 1, 1, 0, 1, 0, 1): b'\xb5',
    (1, 0, 1, 1, 0, 1, 1, 0): b'\xb6',
    (1, 0, 1, 1, 0, 1, 1, 1): b'\xb7',
    (1, 0, 1, 1, 1, 0, 0, 0): b'\xb8',
    (1, 0, 1, 1, 1, 0, 0, 1): b'\xb9',
    (1, 0, 1, 1, 1, 0, 1, 0): b'\xba',
    (1, 0, 1, 1, 1, 0, 1, 1): b'\xbb',
    (1, 0, 1, 1, 1, 1, 0, 0): b'\xbc',
    (1, 0, 1, 1, 1, 1, 0, 1): b'\xbd',
    (1, 0, 1, 1, 1, 1, 1, 0): b'\xbe',
    (1, 0, 1, 1, 1, 1, 1, 1): b'\xbf',
    (1, 1, 0, 0, 0, 0, 0, 0): b'\xc0',
    (1, 1, 0, 0, 0, 0, 0, 1): b'\xc1',
    (1, 1, 0, 0, 0, 0, 1, 0): b'\xc2',
    (1, 1, 0, 0, 0, 0, 1, 1): b'\xc3',
    (1, 1, 0, 0, 0, 1, 0, 0): b'\xc4',
    (1, 1, 0, 0, 0, 1, 0, 1): b'\xc5',
    (1, 1, 0, 0, 0, 1, 1, 0): b'\xc6',
    (1, 1, 0, 0, 0, 1, 1, 1): b'\xc7',
    (1, 1, 0, 0, 1, 0, 0, 0): b'\xc8',
    (1, 1, 0, 0, 1, 0, 0, 1): b'\xc9',
    (1, 1, 0, 0, 1, 0, 1, 0): b'\xca',
    (1, 1, 0, 0, 1, 0, 1, 1): b'\xcb',
    (1, 1, 0, 0, 1, 1, 0, 0): b'\xcc',
    (1, 1, 0, 0, 1, 1, 0, 1): b'\xcd',
    (1, 1, 0, 0, 1, 1, 1, 0): b'\xce',
    (1, 1, 0, 0, 1, 1, 1, 1): b'\xcf',
    (1, 1, 0, 1, 0, 0, 0, 0): b'\xd0',
    (1, 1, 0, 1, 0, 0, 0, 1): b'\xd1',
    (1, 1, 0, 1, 0, 0, 1, 0): b'\xd2',
    (1, 1, 0, 1, 0, 0, 1, 1): b'\xd3',
    (1, 1, 0, 1, 0, 1, 0, 0): b'\xd4',
    (1, 1, 0, 1, 0, 1, 0, 1): b'\xd5',
    (1, 1, 0, 1, 0, 1, 1, 0): b'\xd6',
    (1, 1, 0, 1, 0, 1, 1, 1): b'\xd7',
    (1, 1, 0, 1, 1, 0, 0, 0): b'\xd8',
    (1, 1, 0, 1, 1, 0, 0, 1): b'\xd9',
    (1, 1, 0, 1, 1, 0, 1, 0): b'\xda',
    (1, 1, 0, 1, 1, 0, 1, 1): b'\xdb',
    (1, 1, 0, 1, 1, 1, 0, 0): b'\xdc',
    (1, 1, 0, 1, 1, 1, 0, 1): b'\xdd',
    (1, 1, 0, 1, 1, 1, 1, 0): b'\xde',
    (1, 1, 0, 1, 1, 1, 1, 1): b'\xdf',
    (1, 1, 1, 0, 0, 0, 0, 0): b'\xe0',
    (1, 1, 1, 0, 0, 0, 0, 1): b'\xe1',
    (1, 1, 1, 0, 0, 0, 1, 0): b'\xe2',
    (1, 1, 1, 0, 0, 0, 1, 1): b'\xe3',
    (1, 1, 1, 0, 0, 1, 0, 0): b'\xe4',
    (1, 1, 1, 0, 0, 1, 0, 1): b'\xe5',
    (1, 1, 1, 0, 0, 1, 1, 0): b'\xe6',
    (1, 1, 1, 0, 0, 1, 1, 1): b'\xe7',
    (1, 1, 1, 0, 1, 0, 0, 0): b'\xe8',
    (1, 1, 1, 0, 1, 0, 0, 1): b'\xe9',
    (1, 1, 1, 0, 1, 0, 1, 0): b'\xea',
    (1, 1, 1, 0, 1, 0, 1, 1): b'\xeb',
    (1, 1, 1, 0, 1, 1, 0, 0): b'\xec',
    (1, 1, 1, 0, 1, 1, 0, 1): b'\xed',
    (1, 1, 1, 0, 1, 1, 1, 0): b'\xee',
    (1, 1, 1, 0, 1, 1, 1, 1): b'\xef',
    (1, 1, 1, 1, 0, 0, 0, 0): b'\xf0',
    (1, 1, 1, 1, 0, 0, 0, 1): b'\xf1',
    (1, 1, 1, 1, 0, 0, 1, 0): b'\xf2',
    (1, 1, 1, 1, 0, 0, 1, 1): b'\xf3',
    (1, 1, 1, 1, 0, 1, 0, 0): b'\xf4',
    (1, 1, 1, 1, 0, 1, 0, 1): b'\xf5',
    (1, 1, 1, 1, 0, 1, 1, 0): b'\xf6',
    (1, 1, 1, 1, 0, 1, 1, 1): b'\xf7',
    (1, 1, 1, 1, 1, 0, 0, 0): b'\xf8',
    (1, 1, 1, 1, 1, 0, 0, 1): b'\xf9',
    (1, 1, 1, 1, 1, 0, 1, 0): b'\xfa',
    (1, 1, 1, 1, 1, 0, 1, 1): b'\xfb',
    (1, 1, 1, 1, 1, 1, 0, 0): b'\xfc',
    (1, 1, 1, 1, 1, 1, 0, 1): b'\xfd',
    (1, 1, 1, 1, 1, 1, 1, 0): b'\xfe',
    (1, 1, 1, 1, 1, 1, 1, 1): b'\xff'
    }

def bytes_to_bitlist(buf):
    """Convert a bytes string to a list of bits -0 or 1-
    
    Args:
        buf (bytes) : bytes string
    
    Returns:
        bitlist (list of integer) : list of 0 and 1
    
    Raises:
        KeyError : if `s' is not bytes
    """
    bitlist = []
    [bitlist.extend(BYTETOBIT_LUT[val]) for val in buf]
    return bitlist

def bitlist_to_bytes(bitlist):
    """Convert an iterable of bits -0 or 1- to a bytes string
    
    Args:
        bitlist (iterable of integer) : iterable of 0 and 1
    
    Returns:
        buf (bytes) : bytes string
    
    Raises:
        KeyError : if bitlist contains invalid values
    """
    buf = []
    # cast the iterable to a tuple for dict LU
    bitlist = tuple(bitlist)
    trail = len(bitlist) % 8
    if trail:
        [buf.append(BITTOBYTE_LUT[bitlist[i:i+8]]) \
            for i in range(0, len(bitlist)-trail, 8)]
        buf.append(BITTOBYTE_LUT[bitlist[-trail:] + (8-trail) * (0, )] )
        return b''.join(buf)
    else:
        [buf.append(BITTOBYTE_LUT[bitlist[i:i+8]]) \
            for i in range(0, len(bitlist), 8)]
        return b''.join(buf)

#------------------------------------------------------------------------------#
# bytes buffer functions
#------------------------------------------------------------------------------#

def bytes_lshift(buf=b'', bitlen=0):
    """Shift left a bytes buffer of `bitlen' bits
    
    Args:
        buf (bytes) : bytes string
        bitlen (int) : length in bits
    
    Returns:
        buf_sh (bytes) : shifted bytes string
    """
    if bitlen > 8*len(buf):
        bitlen = 8*len(buf)
    byte_len, bit_len = bitlen>>3, bitlen%8
    # full byte shifting
    buf_sh = buf[byte_len:]
    bl = 8 * len(buf_sh)
    # bit shifting
    if bitlen:
        return uint_to_bytes((bytes_to_uint(buf_sh, bl) << bit_len) & \
                             ((1<<bl)-1), bl)
    else:
        return buf_sh

def bytes_zero_last_bits(buf=b'', bitlen=1):
    """Zero the `bitlen' last bits of the bytes buffer `buf'
    
    Args:
        buf (bytes) : bytes string
        bitlen (integer) : length in bits
    
    Returns:
        buf_z (bytes) : bytes buffer with last bits set to zero
    
    Raises:
        PycrateErr : if `bitlen' is not between 1 and 7 inclusive
    """
    if not 0 < bitlen < 8:
        raise(PycrateErr('bitlen must be between 0 and 8, not inclusive'))
    return buf[:-1] + chr( ord(buf[-1]) & (0x100-(1<<bitlen)) )

def bytes_to_bytelist(buf):
    """Convert a bytes buffer to a list of bytes -uint8-
    
    Args:
        buf (bytes) : bytes string
    
    Returns:
        bytelist (list of integers) : list of uint8 values (0<=X<=255)
    """
    return list(bytearray(buf))

def bytelist_to_bytes(bytelist):
    """Convert a list of bytes -uint8- to a bytes buffer
    
    Args:
        bytelist (list of integer) : list of uint8 values (0<=X<=255)
    
    Returns:
        buf (bytes) : bytes string
    
    Raises:
        ValueError : if bytelist contains invalid values
    """
    return bytes(bytearray(bytelist))

#------------------------------------------------------------------------------#
# bytelist functions
#------------------------------------------------------------------------------#

def bytelist_lshift(bytelist, bitlen=0):
    """Shift left a byte list of `bitlen' bits
    
    Args:
        bytelist (iterable of integer) : iterable of uint8
        bitlen (integer) : length in bits
    
    Returns:
        bytelist_sh (list of integer) : list of uint8
    """
    return list(bytearray(bytes_lshift(bytearray(bytelist), bitlen)))

def uint_to_bytelist(val, bitlen=1):
    """Convert an unsigned integer to a bytelist of `bitlen' length in bits,
    most significant byte is leftmost
    
    Args:
        val (integer) : unsigned integer
        bitlen (integer) : length in bits
    
    Returns:
        bytelist (list of integer) : list of uint8 values (0<=X<=255)
    
    Raises:
        PycrateErr : if `bitlen' is not strictly positive
    """
    return list(bytearray(uint_to_bytes(val, bitlen)))

def bytelist_to_uint(bytelist, bitlen=1):
    """Convert bytelist to an unsigned integer of `bitlen' length in bits,
    most significant byte is leftmost
    
    Args:
        val (integer) : unsigned integer
        bitlen (integer) : length in bits
    
    Returns:
        bytelist (list of integer) : list of uint8 values (0<=X<=255)
    
    Raises:
        PycrateErr : if `bitlen' is not strictly positive
    """
    return bytes_to_uint(bytearray(bytelist), bitlen)

#------------------------------------------------------------------------------#
# integer functions
#------------------------------------------------------------------------------#

def bytes_to_uint(buf, bitlen=1):
    """Convert the leftmost bits of a bytes buffer to an unsigned integer,
    most significant bit leftmost
    
    Args:
        buf (bytes) : bytes string
        bitlen (integer) : length in bits
    
    Returns:
        uint (integer) : unsigned integer value
    
    Raises:
        PycrateErr : if `bitlen' is not strictly positive or if `buf' is not 
        long enough
    """
    # leverage Python2 built-in conversion: str to hex encoding
    if bitlen <= 0:
        raise(PycrateErr('bitlen must be strictly positive'))
    len_byte, len_bit = bitlen>>3, bitlen%8
    if len_bit:
        if len(buf) < len_byte + 1:
            raise(PycrateErr('bytes buffer not long enough'))
        else:
            return int(hexlify(buf[:len_byte+1]), 16) >> (8-len_bit)
    else:
        if len(buf) < len_byte:
            raise(PycrateErr('bytes buffer not long enough'))
        elif len_byte == 1:
            return ord(buf[0])
        elif len_byte == 2:
            return unpack('>H', buf[:2])[0]
        elif len_byte == 4:
            return unpack('>I', buf[:4])[0]
        elif len_byte == 8:
            return unpack('>Q', buf[:8])[0]
        else:
            return int(hexlify(buf[:len_byte]), 16)

def uint_to_bytes(val, bitlen=1):
    """Convert an unsigned integer to a bytes buffer of given length in bits,
    uint with most significant bit leftmost
    
    Args:
        val (integer) : unsigned integer
        bitlen (integer) : length in bits
    
    Returns:
        buf (bytes) : bytes string
    
    Raises:
        PycrateErr : if `bitlen' is not strictly positive
    """
    # Python2 built-in conversion: hex to str decoding
    if bitlen <= 0:
        raise(PycrateErr('bitlen must be strictly positive'))
    len_byte, len_bit = bitlen>>3, bitlen % 8
    # if len_bit, need padding bits appended rightmost
    if val >= (1<<bitlen):
        if len_bit:
            return len_byte * b'\xff' + chr(0x100-(1<<(8-len_bit)))
        else:
            return len_byte * b'\xff'
    elif len_bit == 0:
        if len_byte == 1:
            return chr(val)
        elif len_byte == 2:
            return pack('>H', val)
        elif len_byte == 4:
            return pack('>I', val)
        elif len_byte == 8:
            return pack('>Q', val)
        else:
            len_nib = len_byte * 2
    else:
        val <<= (8-len_bit)
        len_nib = (len_byte + 1) * 2
    h = hex(val)[2:]
    if h[-1] == 'L':
        h= h[:-1]
    if len(h) < len_nib:
        h = (len_nib - len(h)) * '0' + h
    return unhexlify(h)

def bytes_to_uint_le(buf, bitlen=1):
    """Convert the leftmost bits of a bytes buffer to an unsigned integer in 
    little endian format (least significant byte leftmost)
    
    Args:
        buf (bytes) : bytes string
        bitlen (integer) : length in bits, must be a multiple of 8
    
    Returns:
        uint (integer) : unsigned integer value
    
    Raises:
        PycrateErr : if `bitlen' is not strictly positive or not byte-aligned 
            or if `buf' is not long enough
    """
    # leverage Python2 built-in conversion: str to hex encoding
    if bitlen <= 0 or bitlen%8:
        raise(PycrateErr('invalid bitlen for little endian uint: {0}'\
                         .format(bitlen)))
    len_byte = bitlen>>3
    #
    if len(buf) < len_byte:
        raise(PycrateErr('bytes buffer not long enough'))
    elif len_byte == 1:
        return ord(buf[0])
    elif len_byte == 2:
        return unpack('<H', buf[:2])[0]
    elif len_byte == 4:
        return unpack('<I', buf[:4])[0]
    elif len_byte == 8:
        return unpack('<Q', buf[:8])[0]
    else:
        return int(hexlify(buf[len_byte+1::-1]), 16)

def uint_le_to_bytes(val, bitlen=1):
    """Convert an unsigned integer to a bytes buffer of given length in bits,
    uint in little endian format (least significant byte leftmost)
    
    Args:
        val (integer) : unsigned integer
        bitlen (integer) : length in bits, must be a multiple of 8
    
    Returns:
        buf (bytes) : bytes string
    
    Raises:
        PycrateErr : if `bitlen' is not strictly positive or not byte-aligned
    """
    # Python2 built-in conversion: hex to str decoding
    if bitlen <= 0 or bitlen%8:
        raise(PycrateErr('invalid bitlen for little endian uint: {0}'\
                         .format(bitlen)))
    len_byte = bitlen>>3
    #
    if val >= (1<<bitlen):
        return len_byte * b'\xff'
    elif len_byte == 1:
        return chr(val)
    elif len_byte == 2:
        return pack('<H', val)
    elif len_byte == 4:
        return pack('<I', val)
    elif len_byte == 8:
        return pack('<Q', val)
    else:
        len_nib = len_byte * 2
    h = hex(val)[2:]
    if h[-1] == 'L':
        h= h[:-1]
    if len(h) < len_nib:
        h = (len_nib - len(h)) * '0' + h
    return unhexlify(h)[::-1]

def decompose_uint(mul=0x100, val=0):
    """Decompose a value in a list of factors of `mul'
    
    decompose_uint(1<<X, Y) -> [a, b, c, d ...]
        where Y = a + (b << X) + (c << 2X) + (d << 3X) ...
    or
    decompose_uint(X', Y) -> [a, b, c, d ...]
        where Y = a + b * X' + c * X'^2 + d*X'^3 ... 
    
    Args:
        mul (integer) : unsigned integer used as factor
        val (integer) : unsigned integer to be factored
    
    Returns:
        dec (list of integer) : list of factors
    """
    # benefit from Python built-in int() which is pretty fast
    if mul == 2:
        dec = map(int, bin(val)[2:])
        dec.reverse()
        return dec
    elif mul == 16 and val >= 10000000000:
        h = hex(val)[2:]
        if h[-1] == 'L': h = h[:-1]
        dec = map(int, h, len(h)*[16])
        dec.reverse()
        return dec
    # decompose simply by iterative division
    else:
        dec = [ int(val % mul) ]
        while val >= mul:
            val //= mul
            dec.append( int(val % mul) )
        return dec

def swap_uint(uint, bitlen):
    """Swap the endianness of the unsigned integer uint of length bitlen
    
    Args:
        uint (unsigned integer)
        bitlen (unsigned integer)
    
    Returns:
        uint (unsigned integer)
    """
    if bitlen < 0 or bitlen % 8:
        raise(PycrateErr('invalid bitlen of little endian uint: {0}'\
              .format(bitlen)))
    len_byte, ret = bitlen>>3, []
    for i in range(len_byte>>1):
        bi  = 8*i
        rbi = bitlen-8-bi
        ret.append( (uint & (0xff<<bi)) << (rbi-bi) )
        ret.append( (uint & (0xff<<rbi)) >> (rbi-bi) )
    if len_byte % 2:
        ret.append( uint & (0xff<<(8*(len_byte>>1))) )
    return sum(ret)

#------------------------------------------------------------------------------#
# concatenation
#------------------------------------------------------------------------------#

def bytes_lshift_bnd(buf, buflen=8, shlen=1):
    """Shift left of `shlen' bits the bytes buffer `buf' of length in bits 
    `buflen' with 0 < shlen < 8
    
    provide the heading value of `shlen' bits that leaves the buffer
            the shifted buffer, fully byte-aligned (can be of size 0)
            the trailing value of remaining bits (can be None)
    
    Args:
        buf (bytes) : bytes string
        buflen (integer) : length in bits of the bytes buffer
        shlen (integer) : value of the shift, between 1 and 7
    
    Returns:
        tuple of (integer, bytes, integer or None)
    """
    if buflen <= shlen:
        # only heading bits
        head = (ord(buf[0]) & (0x100 - (1<<(8-buflen)))) >> (8-shlen)
        return head, b'', None
    elif buflen < 8 + shlen:
        # only heading and trailing bits
        head = ord(buf[0]) >> (8-shlen)
        buf = bytes_lshift(buf, shlen)
        trail = ord(buf[0]) & (0x100 - (1<<(8-buflen+shlen)))
        return head, b'', trail
    #
    head = ord(buf[0])>>(8-shlen)
    buf = bytes_lshift(buf, shlen)
    restlen = buflen % 8
    if restlen == 0:
        trail = ord(buf[-1]) 
        buf = buf[:-1]
    elif restlen < shlen:
        trail = ord(buf[-2]) & (0x100 - (1<<(shlen-restlen)))
        buf = buf[:-2]
    elif restlen == shlen:
        trail = None
        buf = buf[:-1]
    else:
        trail = ord(buf[-1]) & (0x100 - (1<<(8+shlen-restlen)))
        buf = buf[:-1]
    return head, buf, trail


TYPE_BYTES  = 1
TYPE_UINT = 2
TYPE_INT  = 3
TYPE_UINT_LE = 12
TYPE_INT_LE = 13
#
FMT_INT   = {
    8 : 'b',
    16: 'h',
    32: 'i',
    64: 'q'
    }
FMT_UINT  = {
    8 : 'B',
    16: 'H',
    32: 'I',
    64: 'Q'
    }
FMT_LUT   = {
    2: FMT_UINT,
    3: FMT_INT,
    12: FMT_UINT,
    13: FMT_INT
    }
#
PACK_FMT_BE = 0
PACK_FMT_LE = 1

def pack_val(*val):
    """Packs heterogenous bytes buffer and (un)signed integers, all with a given
    length in bits, to a resulting bytes buffer
    
    Args:
        val (tuple) : tuple of (type, value, bitlen)
            type must be TYPE_BYTES, TYPE_UINT or TYPE_INT
            value must be a bytes string or an integer, according to type
            bitlen must be an integer over 0
    
            warning: for TYPE_UINT_LE and TYPE_INT_LE, bitlen must be a multiple
            of 8 (hence the value will be byte-aligned)
    
    Returns:
        buf (tuple of (bytes, integer)) : a tuple containing the actual 
            resulting bytes string and the length in bits 
    
    Example:
        pack_val( (TYPE_BYTES, 'AAAA\xC0', 34),
                  (TYPE_UINT, 2500, 32),
                  (TYPE_UINT, 10000000000, 64),
                  (TYPE_INT, -1, 8),
                  (TYPE_BYTES, 'bbbbbb', 48),
                  (TYPE_INT, -2000, 54),
                  (TYPE_UINT, 1, 2),
                  (TYPE_BYTES, '\0', 7) )
            -> (b'AAAA\xc0\x00\x02q\x00\x00\x00\x00\x95\x02\xf9\x00?'\
                '\xd8\x98\x98\x98\x98\x98?\xff\xff\xff\xff\xf80@\x00',
                249)
    """
    # global resulting byte buffer
    concat, len_bit = [], 0
    # junction byte when unaligned values are concatenated
    junc = None
    # cumulative processing for int / uint
    pack_fmt, pack_val, pack_end, pack_len = None, None, PACK_FMT_BE, 0
    
    for v in val:
        #print('val     : {0}, {1}, {2}'.format(*v))
        #print('pack    : fmt {0}, val {1}'.format(pack_fmt, pack_val))
        #print('junc    : {0}'.format(junc))
        #print('len_bit : {0}'.format(len_bit))
        #print('concat  : {0}'.format(concat))
        #print('')
        #
        rest_bit = len_bit%8
        #
        # 0) bypass null field
        if v[2] == 0:
            pass
        #
        # 1) cumulative processing for 8/16/32/64 bits big endian (u)int
        elif v[0] in (TYPE_INT, TYPE_UINT) and v[2] in (8, 16, 32, 64):
            if pack_end == PACK_FMT_LE and pack_fmt is not None:
                # a) append previous integers that were little endian
                pack_buf = pack(''.join(pack_fmt), *pack_val)
                if rest_bit == 0:
                    # a.a) aligned access
                    assert( junc is None )
                    concat.append(pack_buf)
                    len_bit += pack_len
                else:
                    # a.b) unaligned access
                    assert( 0 <= junc < 256 )
                    head, buf, trail = bytes_lshift_bnd(pack_buf, pack_len, 8-rest_bit)
                    # complete the junction byte and append it 
                    # with the shifted buffer
                    len_bit += pack_len
                    if buf:
                        # heading bits, buffer and potential trailing bits
                        concat.extend( (chr(junc + head), buf) )
                        junc = trail
                    elif trail is not None:
                        # heading bits and potential trailing bits
                        concat.append( chr(junc + head) )
                        junc = trail
                    elif not len_bit % 8:
                        # heading bits only
                        concat.append( chr(junc + head) )
                        junc = None
                    else:
                        # no buf and no trailing bits
                        junc += head
                pack_fmt, pack_val, pack_end, pack_len = None, None, PACK_FMT_BE, 0
            #
            # b) accumulate value into pack_val
            if pack_fmt is None:
                pack_fmt = ['>', FMT_LUT[v[0]][v[2]]]
                pack_val = [v[1]]
            else:
                pack_fmt.append( FMT_LUT[v[0]][v[2]] )
                pack_val.append( v[1] )
            pack_len += v[2]
        #
        # 2) cumulative processing for 8/16/32/64 bits little endian (u)int
        elif v[0] in (TYPE_INT_LE, TYPE_UINT_LE) and v[2] in (8, 16, 32, 64):
            # a) append previous integers if were big endian
            if pack_end == PACK_FMT_BE and pack_fmt is not None:
                pack_buf = pack(''.join(pack_fmt), *pack_val)
                if rest_bit == 0:
                    # a.a) aligned access
                    assert( junc is None )
                    concat.append(pack_buf)
                    len_bit += pack_len
                else:
                    # a.b) unaligned access
                    assert( 0 <= junc < 256 )
                    head, buf, trail = bytes_lshift_bnd(pack_buf, pack_len, 8-rest_bit)
                    # complete the junction byte and append it 
                    # with the shifted buffer
                    len_bit += pack_len
                    if buf:
                        # heading bits, buffer and potential trailing bits
                        concat.extend( (chr(junc + head), buf) )
                        junc = trail
                    elif trail is not None:
                        # heading bits and potential trailing bits
                        concat.append( chr(junc + head) )
                        junc = trail
                    elif not len_bit % 8:
                        # heading bits only
                        concat.append( chr(junc + head) )
                        junc = None
                    else:
                        # no buf and no trailing bits
                        junc += head
                pack_fmt, pack_val, pack_end, pack_len = None, None, PACK_FMT_BE, 0
            #
            # b) accumulate value into pack_val
            if pack_fmt is None:
                pack_end = PACK_FMT_LE
                pack_fmt = ['<', FMT_LUT[v[0]][v[2]]]
                pack_val = [v[1]]
            else:
                pack_fmt.append( FMT_LUT[v[0]][v[2]] )
                pack_val.append( v[1] )
            pack_len += v[2]
        #
        # 3) standard processing for bytes buffer
        elif v[0] == TYPE_BYTES:
            # a) append pack_val first, if exist
            if pack_fmt is not None:
                pack_buf = pack(''.join(pack_fmt), *pack_val)
                if rest_bit == 0:
                    # a.a) aligned access
                    assert( junc is None )
                    concat.append(pack_buf)
                    len_bit += pack_len
                    #
                    concat.append(v[1][:v[2]>>3])
                    if v[2]%8:
                        # remaining bits goes to junction byte
                        junc = ord(v[1][v[2]>>3]) & (0x100 - (1<<(8-v[2]%8)))
                    len_bit += v[2]
                #
                else:
                    # a.b) unaligned access
                    assert( 0 <= junc < 256 )
                    if v[2] % 8:
                        buf = pack_buf + v[1][:1+(v[2]>>3)]
                    else:
                        buf = pack_buf + v[1][:v[2]>>3]
                    buflen = pack_len + v[2]
                    head, buf, trail = bytes_lshift_bnd(buf, buflen, 8-rest_bit)
                    # complete the junction byte and append it 
                    # with the shifted buffer
                    len_bit += buflen
                    if buf:
                        # heading bits, buffer and potential trailing bits
                        concat.extend( (chr(junc + head), buf) )
                        junc = trail
                    elif trail is not None:
                        # heading bits and potential trailing bits
                        concat.append( chr(junc + head) )
                        junc = trail
                    elif not len_bit % 8:
                        # heading bits only
                        concat.append( chr(junc + head) )
                        junc = None
                    else:
                        # no buf and no trailing bits
                        junc += head
                #
                pack_fmt, pack_val, pack_end, pack_len = None, None, PACK_FMT_BE, 0
            #
            # b) nothing to pack
            elif rest_bit == 0:
                # b.a) aligned access
                assert( junc is None )
                if v[2] < 8:
                    junc = ord(v[1][0]) & (0x100 - (1<<(8-v[2])))
                else:
                    concat.append( v[1][:v[2]>>3] )
                    if v[2] % 8:
                        # remaining bits goes to junction byte
                        junc = ord(v[1][v[2]>>3]) & (0x100 - (1<<(8-v[2]%8)))
                len_bit += v[2]
            #
            else:
                # b.b) unaligned access
                assert( 0 <= junc < 256 )
                if v[2] % 8:
                    head, buf, trail = bytes_lshift_bnd(v[1][:1+(v[2]>>3)],
                                                        v[2], 8-rest_bit)
                else:
                    head, buf, trail = bytes_lshift_bnd(v[1][:v[2]>>3],
                                                        v[2], 8-rest_bit)
                # complete the junction byte and append it 
                # with the shifted buffer
                len_bit += v[2]
                if buf:
                    # heading bits, buffer and potential trailing bits
                    concat.extend( (chr(junc + head), buf) )
                    junc = trail
                elif trail is not None:
                    # heading bits and potential trailing bits
                    concat.append( chr(junc + head) )
                    junc = trail
                elif not len_bit % 8:
                    # heading bits only
                    concat.append( chr(junc + head) )
                    junc = None
                else:
                    # no buf and no trailing bits
                    junc += head
        #
        # 4) standard processing for uint
        elif v[0] == TYPE_UINT:
            # a) append pack_val first, if exist
            if pack_fmt is not None:
                pack_buf = pack(''.join(pack_fmt), *pack_val)
                if rest_bit == 0:
                    # a.a) aligned access
                    assert( junc is None )
                    concat.append(pack_buf)
                    len_bit += pack_len
                    #
                    buf = uint_to_bytes(v[1], v[2])
                    concat.append(buf[:v[2]>>3])
                    if v[2]%8:
                        # remaining bits goes to junction byte
                        junc = ord(buf[v[2]>>3])
                    len_bit += v[2]
                #
                else:
                    # a.b) unaligned access
                    assert( 0 <= junc < 256 )
                    # first shift the existing packed buffer
                    # TODO: this may be faster to shift integer values before 
                    # packing them; however, this will break their format and 
                    # cause me more headache
                    head, buf, trail = bytes_lshift_bnd(pack_buf, 
                                                        pack_len, 8-rest_bit)
                    if buf:
                        concat.extend( (chr(junc + head), buf) )
                    else:
                        concat.append( chr(junc + head) )
                    # pack_buf is always byte-aligned,
                    # so there are always trailing bits
                    junc = trail
                    u = v[1] & ((1<<v[2])-1)
                    # heading bits from the uint value to pack
                    if v[2] < 8-rest_bit:
                        junc += u << (8-rest_bit-v[2])
                    elif v[2] == 8-rest_bit:
                        concat.append( chr(junc + u) )
                        junc = None
                    else:
                        lb = v[2]-8+rest_bit
                        concat.append( chr(junc + (u>>lb)) )
                        if lb >= 8:
                            # body of the uint value
                            lt = lb%8
                            if lt == 0:
                                # no trailing bits
                                concat.append( uint_to_bytes(u&((1<<lb)-1), lb) )
                                junc = None
                            else:
                                # with trailing bits
                                concat.append( uint_to_bytes((u&((1<<lb)-1))>>lt,
                                                           lb-lt) )
                                junc = (u&((1<<lt)-1))<<(8-lt)
                        else:
                            # no body, only trailing bits
                            junc = (u&((1<<lb)-1))<<(8-lb)
                    len_bit += pack_len + v[2]
                #
                pack_fmt, pack_val, pack_end, pack_len = None, None, PACK_FMT_BE, 0  
            #
            # b) nothing to pack
            elif len_bit % 8 == 0:
                # b.a) aligned access
                assert( junc is None )
                if v[2] < 8:
                    if v[1] >= (1<<v[2]):
                        junc = 0x100 - (1<<(8-v[2]))
                    else:
                        junc = v[1] << (8-v[2])
                else:
                    buf = uint_to_bytes(v[1], v[2])
                    concat.append(buf[:v[2]>>3])
                    if v[2]%8:
                        # remaining bits goes to junction byte
                        junc = ord(buf[v[2]>>3])
                len_bit += v[2]
            #
            else:
                # b.b) unaligned access
                assert( 0 <= junc < 256 )
                u = v[1] & ((1<<v[2])-1)
                # heading bits from the uint value to pack
                if v[2] < 8-rest_bit:
                    junc += u << (8-rest_bit-v[2])
                elif v[2] == 8-rest_bit:
                    concat.append( chr(junc + u) )
                    junc = None
                else:
                    lb = v[2]-8+rest_bit
                    concat.append( chr(junc + (u>>lb)) )
                    if lb >= 8:
                        #  body of the uint value
                        lt = lb%8
                        if lt == 0:
                            # no trailing bits
                            concat.append( uint_to_bytes(u&((1<<lb)-1), lb) )
                            junc = None
                        else:
                            # with trailing bits
                            concat.append( uint_to_bytes((u&((1<<lb)-1))>>lt,
                                                       lb-lt) )
                            junc = (u&((1<<lt)-1))<<(8-lt)
                    else:
                        # no body, only trailing bits
                        junc = (u&((1<<lb)-1))<<(8-lb)
                len_bit += v[2]
        #
        # 5) standard processing for int
        elif v[0] == TYPE_INT:
            #
            if v[1] >= 0:
                u = v[1]&((1<<v[2]-1)-1)
            else:
                # take 2's complement, so we only manipulate uint
                u = v[1]+(1<<v[2])
                if u < (1<<(v[2]-1)):
                    u = 1<<(v[2]-1)
            #
            # a) append pack_val first, if exist
            if pack_fmt is not None:
                pack_buf = pack(''.join(pack_fmt), *pack_val)
                if rest_bit == 0:
                    # a.a) aligned access
                    assert( junc is None )
                    concat.append(pack_buf)
                    len_bit += pack_len
                    #
                    buf = uint_to_bytes(u, v[2])
                    concat.append(buf[:v[2]>>3])
                    if v[2]%8:
                        # remaining bits goes to junction byte
                        junc = ord(buf[v[2]>>3])
                    len_bit += v[2]
                #
                else:
                    # a.b) unaligned access
                    assert( 0 <= junc < 256 )
                    # first shift the existing packed buffer
                    # TODO: this may be faster to shift integer values before 
                    # packing them; however, this will break their format and 
                    # cause me more headache
                    head, buf, trail = bytes_lshift_bnd(pack_buf, 
                                                        pack_len, 8-rest_bit)
                    if buf:
                        concat.extend( (chr(junc + head), buf) )
                    else:
                        concat.append( chr(junc + head) )
                    # pack_buf is always byte-aligned,
                    # so there are always trailing bits
                    junc = trail
                    #
                    # heading bits from the uint value to pack
                    if v[2] < 8-rest_bit:
                        junc += u << (8-rest_bit-v[2])
                    elif v[2] == 8-rest_bit:
                        concat.append( chr(junc + u) )
                        junc = None
                    else:
                        lb = v[2]-8+rest_bit
                        concat.append( chr(junc + (u>>lb)) )
                        if lb >= 8:
                            # body of the uint value
                            lt = lb%8
                            if lt == 0:
                                # no trailing bits
                                concat.append( uint_to_bytes(u&((1<<lb)-1), lb) )
                                junc = None
                            else:
                                # with trailing bits
                                concat.append( uint_to_bytes((u&((1<<lb)-1))>>lt,
                                                           lb-lt) )
                                junc = (u&((1<<lt)-1))<<(8-lt)
                        else:
                            # no body, only trailing bits
                            junc = (u&((1<<lb)-1))<<(8-lb)
                    len_bit += pack_len + v[2]
                #
                pack_fmt, pack_val, pack_end, pack_len = None, None, PACK_FMT_BE, 0   
            #
            # b) nothing to pack
            elif len_bit % 8 == 0:
                # b.a) aligned access
                assert( junc is None )
                if v[2] < 8:
                    junc = u << (8-v[2])
                else:
                    buf = uint_to_bytes(u, v[2])
                    concat.append(buf[:v[2]>>3])
                    if v[2]%8:
                        # remaining bits goes to junction byte
                        junc = ord(buf[v[2]>>3])
                len_bit += v[2]
            #
            else:
                # b.b) unaligned access
                assert( 0 <= junc < 256 )
                # heading bits from the uint value to pack
                if v[2] < 8-rest_bit:
                    junc += u << (8-rest_bit-v[2])
                elif v[2] == 8-rest_bit:
                    concat.append( chr(junc + u) )
                    junc = None
                else:
                    lb = v[2]-8+rest_bit
                    concat.append( chr(junc + (u>>lb)) )
                    if lb >= 8:
                        #  body of the uint value
                        lt = lb%8
                        if lt == 0:
                            # no trailing bits
                            concat.append( uint_to_bytes(u&((1<<lb)-1), lb) )
                            junc = None
                        else:
                            # with trailing bits
                            concat.append( uint_to_bytes((u&((1<<lb)-1))>>lt,
                                                       lb-lt) )
                            junc = (u&((1<<lt)-1))<<(8-lt)
                    else:
                        # no body, only trailing bits
                        junc = (u&((1<<lb)-1))<<(8-lb)
                len_bit += v[2]
        #
        # 6) standard processing for little-endian integers
        elif v[0] in (TYPE_UINT_LE, TYPE_INT_LE):
            if v[0] == TYPE_UINT_LE:
                v_bytes = uint_le_to_bytes(v[1], v[2])
            else:
                if v[1] >= 0:
                    u = v[1]&((1<<v[2]-1)-1)
                else:
                    # take 2's complement, so we only manipulate uint
                    u = v[1]+(1<<v[2])
                    if u < (1<<(v[2]-1)):
                        u = 1<<(v[2]-1)
                v_bytes = uint_le_to_bytes(u, v[2])
            # a) append pack_val first, if exist
            if pack_fmt is not None:
                pack_buf = pack(''.join(pack_fmt), *pack_val)
                if rest_bit == 0:
                    # a.a) aligned access
                    assert( junc is None )
                    concat.append(pack_buf)
                    len_bit += pack_len
                    #
                    concat.append(v_bytes)
                    len_bit += v[2]
                #
                else:
                    # a.b) unaligned access
                    assert( 0 <= junc < 256 )
                    buf = pack_buf + v_bytes
                    buflen = pack_len + v[2]
                    head, buf, trail = bytes_lshift_bnd(buf, buflen, 8-rest_bit)
                    # complete the junction byte and append it 
                    # with the shifted buffer
                    len_bit += buflen
                    if buf:
                        # heading bits, buffer and potential trailing bits
                        concat.extend( (chr(junc + head), buf) )
                        junc = trail
                    elif trail is not None:
                        # heading bits and potential trailing bits
                        concat.append( chr(junc + head) )
                        junc = trail
                    elif not len_bit % 8:
                        # heading bits only
                        concat.append( chr(junc + head) )
                        junc = None
                    else:
                        # no buf and no trailing bits
                        junc += head
                #
                pack_fmt, pack_val, pack_end, pack_len = None, None, PACK_FMT_BE, 0
            #
            # b) nothing to pack
            elif rest_bit == 0:
                # b.a) aligned access
                assert( junc is None )
                concat.append(v_bytes)
                len_bit += v[2]
            #
            else:
                # b.b) unaligned access
                assert( 0 <= junc < 256 )
                head, buf, trail = bytes_lshift_bnd(v_bytes, v[2], 8-rest_bit)
                # complete the junction byte and append it 
                # with the shifted buffer
                len_bit += v[2]
                if buf:
                    # heading bits, buffer and potential trailing bits
                    concat.extend( (chr(junc + head), buf) )
                    junc = trail
                elif trail is not None:
                    # heading bits and potential trailing bits
                    concat.append( chr(junc + head) )
                    junc = trail
                elif not len_bit % 8:
                    # heading bits only
                    concat.append( chr(junc + head) )
                    junc = None
                else:
                    # no buf and no trailing bits
                    junc += head
                
        #
        else:
            raise(PycrateErr('invalid type for packing: {0}'.format(v[0])))
    #
    #print('pack    : fmt {0}, val {1}'.format(pack_fmt, pack_val))
    #print('junc    : {0}'.format(junc))
    #print('len_bit : {0}'.format(len_bit))
    #print('concat  : {0}'.format(concat))
    #print('')
    #
    # 5) in case some integers to pack remains
    if pack_val is not None:
        rest_bit = len_bit%8
        pack_buf = pack(''.join(pack_fmt), *pack_val)
        if rest_bit == 0:
            # a) aligned access
            assert( junc is None )
            concat.append(pack_buf)
            len_bit += pack_len
        else:
            # b) unaligned access
            assert( 0 <= junc < 256 )
            # TODO: again, this may be faster to shift integer values before 
            # packing them...
            head, buf, trail = bytes_lshift_bnd(pack_buf, pack_len, 8-rest_bit)
            # complete the junction byte and append it 
            # with the shifted buffer
            if buf:
                concat.extend( (chr(junc + head), buf) )
                junc = trail
            else:
                concat.append( chr(junc + head) )
                junc = trail
            len_bit += pack_len
        #
        pack_fmt, pack_val, pack_len = None, None, 0
    #
    #print('junc    : {0}'.format(junc))
    #print('len_bit : {0}'.format(len_bit))
    #print('concat  : {0}'.format(concat))
    #print('')
    #
    # 6) pack the remaining junction byte
    if junc is not None:
        concat.append( chr(junc) )
    #
    # 7) return the length in bits and bytes buffer
    return b''.join(concat), len_bit
